<?php
/**
 * @package Joomla
 * @subpackage Fabrik
 * @copyright Copyright (C) 2005 Rob Clayburn. All rights reserved.
 * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
 */

// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die();

jimport('joomla.application.component.model');
require_once(COM_FABRIK_FRONTEND.DS.'helpers'.DS.'string.php');


class FabrikModelCSVExport {

	/** int number of records to output at a time */
	var $step = 100;


	public function _getStep()
	{
		return $this->model->getParams()->get('csv_export_step', $this->step);
	}

	function writeFile($total)
	{
		$app =& JFactory::getApplication();
		jimport('joomla.filesystem.file');
		$start = JRequest::getInt('start', 0);
		$filename = $this->getFileName();
		$filepath = $this->getFilePath();
		$str = '';
		if (JFile::exists($filepath)) {
			if ($start === 0) {
				JFile::delete($filepath);
			}else{
				$str = JFile::read($filepath);
			}
		} else {
			JFile::write($filepath, '');
			$str = '';
		}

		$session =& JFactory::getSession();
		$table 	=& $this->model->getTable();
		$this->model->render();
		$this->removePkVal();
		if ($start === 0) {
			$headings = $this->getHeadings();
			if (empty($headings)) {
				$url = JRequest::getVar('HTTP_REFERER', '', 'server');
				$app->redirect($url, JText::_('No data to export'));
				return;
			}

			$str .= implode($headings, COM_FABRIK_CSV_DELIMITER) . "\n";
		}

		$incRaw = JRequest::getVar('incraw', true);
		$incData = JRequest::getVar('inctabledata', true);

		$data =& $this->model->getData();
		$exportFormat = $this->model->getParams()->get('csvfullname');
		$shortkey = FabrikString::shortColName($table->db_primary_key);

		foreach ($data as $group) {
			foreach ($group as $row) {

				$a = JArrayHelper::fromObject($row);
				if ($exportFormat == 1) {
					unset($a[$shortkey]);
				}
				if (!$incRaw) {
					foreach ($a as $key=>$val) {
						if (substr($key, strlen($key) - 4, strlen($key)) == "_raw") {
							unset($a[$key]);
						}
					}
				}
				if (!$incData) {
					foreach ($a as $key=>$val) {
						if (substr($key, strlen($key) - 4, strlen($key)) != "_raw") {
							unset($a[$key]);
						}
					}
				}

				if (JRequest::getVar('inccalcs') == 1) {
					array_unshift($a, ' ');
				}
				$this->carriageReutrnFix($a);
				$str .= implode(COM_FABRIK_CSV_DELIMITER, array_map(array($this, "_quote"), array_values($a)));
				$str .= "\n";
			}
		}
		$res = new stdClass();
		$res->total = $total;
		$res->count = $start + $this->_getStep();
		$res->file= $filepath;
		$res->limitStart = $start;
		$res->limitLength = $this->_getStep();
		if ($res->count >= $res->total) {
			$this->_addCalculations($a, $str);
		}
		JFile::write($filepath, $str);
		echo FastJSON::encode($res);
	}

	private function carriageReutrnFix(&$row)
	{
		$newline = $this->model->getParams()->get('newline_csv_export', 'nl');
		switch ($newline) {
			default:
			case 'nl2br':
				if (is_array($row)) {
					foreach($row as &$val) {
						$val = nl2br( $val);
						$val = str_replace(array("\n", "\r", "\n\r", "\r\n"), '', $val);
					}
				} else {
					$row = nl2br( $row);
						$row = str_replace(array("\n", "\r", "\n\r", "\r\n"), '',  $row);
				}
				break;
			case 'nl':

				break;
			case 'remove':
				if (is_array($row)) {
					foreach($row as &$val) {
						$val = str_replace(array("\n", "\r", "\n\r", "\r\n"), '', $val);
					}
				} else {
					$row = str_replace(array("\n", "\r", "\n\r", "\r\n"), '', $row);
				}
				break;
		}
	}

	private function getFileName()
	{
		$this->model->setId(JRequest::getInt('tableid'));
		$table 	=& $this->model->getTable();
		$filename = $table->db_table_name.'-export.csv';
		return $filename;
	}

	private function getFilePath()
	{
		$filename = $this->getFileName();
		return JPATH_SITE.DS.'tmp'.DS.$filename;
	}

	public function downloadFile()
	{
		jimport('joomla.filesystem.file');
		$filename = $this->getFileName();
		$filepath = $this->getFilePath();
		$document = JFactory::getDocument();
		$document->setMimeEncoding('application/zip');

		$str = JFile::read($filepath);
		// Set the response to indicate a file download
		JResponse::setHeader('Content-Type', 'application/zip');
		JResponse::setHeader('Content-Disposition', 'attachment; filename="'.$filename.'"');

		JResponse::setBody($str);
		echo JResponse::toString(false);
		JFile::delete($filepath);
	}

	/**
	 * add calculations
	 *
	 * @param array of field elements $a
	 * @param string to out put as csv file $str
	 */

	function _addCalculations($a, &$str)
	{
		if (JRequest::getVar('inccalcs') == 1) {

			$calkeys = array('sums', 'avgs', 'medians', 'count');

			foreach ($calkeys as $calkey) {
				$aCalcs[$calkey] = array_fill(0, count($a)+1, ' ');
				$aCalcs[$calkey][0] = $calkey;
				$calcs = $this->model->_aRunCalculations;
				foreach ($calcs[$calkey] as $key => $cal) {

					$x = 0;
					$found = false;
					// $$$rob if grouped data and calc split then get the formatted string as $cal['calc] wont exist below
					foreach ($a as $akey=>$aval) {
						if (trim($akey) == trim($key) && $x != 0) {
							$default = $calcs[$calkey][$akey];
						}
						$x ++;
					}
					$x = 0;

					foreach ($a as $akey=>$aval) {
						if ($akey == substr($key, 0, strlen($key)-4)&& $x != 0) {
							$found = true;
							break;
						}
						$x ++;
					}
					if ($found) {
						if (array_key_exists('calc', $cal)) {
							$aCalcs[$calkey][$x] = $cal['calc']->value;
						} else {
							$aCalcs[$calkey][$x] = $default;
						}
					}
				}
				$str .= implode(COM_FABRIK_CSV_DELIMITER, array_map(array($this, "_quote"), array_values($aCalcs[$calkey])));
				$str .= "\n";
			}
		}
	}

	function _quote($n)
	{
		return '"'.str_replace('"', '""', $n).'"';
	}

	/**
	 * get the headings for the csv file
	 * @return array heading labels
	 */

	function getHeadings()
	{
		$table 	    =& $this->model->getTable();
		$params 		=& $this->model->getParams();
		$hformat 		= $params->get('csvfullname');
		$data 			=& $this->model->getData();
		$headings 	= array();
		$g =& current($data);
		if (empty($g)) {
			return $g;
		}
		$selectedFields = JRequest::getVar('fields');
		$r =& current($g);
		$formModel =& $this->model->getForm();
		$groups =& $formModel->getGroupsHiarachy();
		$h = array();
		if (!is_object($r)) {
			return new stdClass();
		}
		$incRaw = JRequest::getVar('incraw', true);
		$incData = JRequest::getVar('inctabledata', true);

		$shortkey = FabrikString::shortColName($table->db_primary_key);

		foreach ($r as $heading => $value) {
			$found = false;
			foreach ($groups as $groupModel) {
				$elementModels =& $groupModel->getPublishedElements();
				foreach ($elementModels as $elementModel) {
					$element =& $elementModel->getElement();
					$fullname = $elementModel->getFullName(false, true, false);

					if ($fullname == $heading || $fullname . "_raw" == $heading) {
						$found = true;
						switch ($hformat) {
							default:
							case '0':
								$n = $element->name;
								break;
							case '1':
								$n = $elementModel->getFullName(false, false, false);
								break;
							case '2':
								$headingLabel = $elementModel->getParams()->get('element_alt_table_heading');
								$n = trim($headingLabel) === '' ? $element->label : $headingLabel;
								break;
						}

						if ($fullname . "_raw" == $heading) {
							$n .= "_raw";
						}

						if ($incData && substr($n, strlen($n)-4, strlen($n)) !== '_raw') {
							if (!in_array($n, $h)) { //only add heading once
								$h[] = $n;
							}
						}

						if ($incRaw && substr($n, strlen($n)-4, strlen($n)) == "_raw") {
							if (!in_array($n, $h)) { //only add heading once
								$h[] = $n;
							}
						}
					}
				}
			}

			if (!$found) {
				if (!(substr($heading, strlen($heading)-4, strlen($heading)) == "_raw" && !$incRaw)) {
					//stop id getting added to tables when exported wiht fullelname key
					if ($hformat != 1 && $heading != $shortkey) {
						$h[] = $heading;
					}
				}
			}
		}
		if (JRequest::getVar('inccalcs') == 1) {
			array_unshift($h, JText::_('Calculation'));
		}

		$h = array_map(array($this, "_quote"), $h);
		return $h;
	}

	/*
	 * Remove the __pk_val from data
	 */
	function removePkVal()
	{
		$data =& $this->model->getData();
		foreach ($data as $group) {
			foreach ($group as $row) {
				unset($row->__pk_val);
			}
		}
	}
}