<?php

namespace common\controllers;

use Yii;
use common\models\User;
use yii\web\Controller;
use yii\base\Security;
use common\models\CartForm;
use common\controllers\CommonDBInterface as DBInterface;
use common\models\CheckoutForm;
use ggbn\SOLRQueryManager;


/**
 * This Controller is responsible for all actions concerning the shopping system.
 * @author a.hartebrodt
 *
 */
class CommonCartController extends Controller {

	/**
	 * Overrides the parent method to assure that the call is made by an logged in user
	 *
	 * @see \yii\web\Controller::beforeAction()
	 */
	public function beforeAction($action) {
		if (! parent::beforeAction ( $action )) {
			return false;
		}

		if (Yii::$app->user->isGuest ) {
			$this->goHome ();
		} else {
			if (Yii::$app->session ['userSessionTimeout'] < time ()) {
				Yii::$app->user->logout ();
				$this->goHome ();
				Yii::$app->session->setFlash ( 'success', 'You have been logged out!' );
			} else {
				Yii::$app->session->set ( 'userSessionTimeout', time () + Yii::$app->params ['sessionTimeoutSeconds'] );
				return true;
			}
		}

		return true; // or false to not run the action
	}

	/**
	 * Function that adds the checked samples to the shopping cart.
	 */
	public function actionAdd() {
		if (Yii::$app->request->isAjax) {
			$user = Yii::$app->user->id;
			$array = Yii::$app->getRequest ()->getBodyParams ()['CartForm'];
			$final = $array ['checked'];

			// "/" were replaced by "SLASH" in the var names it needs to be re-replaced during
			//entry in shopping cart.
			foreach ($final as $key =>$value){
				if(preg_match('*SLASH*', $key)){
				unset($final[$key]);
				$final[str_replace('SLASH', '/',$key)] = $value;
				}
			}
			DBInterface::addToShoppingCart ( $final, $user );
		}
	}

	/**
	 * function updating the pjax widget, which shows the shopping cart content.
	 * @return string
	 */
	public function actionAddedlist(){
		$shoppingCart = sizeof(DBInterface::getShoppingCart(Yii::$app->user->identity->id));
		return $this->renderPartial('addedlist', ['shoppingCart'=>$shoppingCart]);
	}

	/**
	 * function which adds one sample to the shopping cart, given a unit id. It also updates the pjax
	 * widget. This function is called on the single record sites.
	 * @param unknown $unitID
	 */
	public function actionAddone($unitID, $collectionCode, $institutionCode){
		var_dump($unitID);
		var_dump($collectionCode);
		var_dump($institutionCode);
		DBInterface::addToShoppingCart([($unitID."---".$collectionCode."---".$institutionCode)=>'1'], Yii::$app->user->id);
		$this->renderAjax('added');

	}

	/**
	 * renders the shopping cart primary site.
	 * @return Ambigous <string, string>
	 */
	public function actionCart() {
		$user = Yii::$app->user->identity->id;
		$cartContent = DBInterface::getShoppingCart ( $user );
		$ids = array_column ( $cartContent, 'unit_id' ); 
		$colcodes = array_column ( $cartContent, 'collection_code' );
		$instcodes = array_column ( $cartContent, 'institution_code' );
		$cartInfo = [ ];
		$documents = [ ];
		$i=0;
		foreach ( $ids as $id ) {
			$doc = $this->getInfo ( $id, $colcodes[$i], $instcodes[$i] );
			array_push ( $documents, $doc );
			//var_dump ( $doc );
			$ar = $this->getLowest ( $doc );
			$cites = false;
			if($doc[$ar[1]]['citesStatus']!="N/A"){
				$cites = true;
			}
			//Write the necessary information into an array.
			$cartInfo [$ar [0]] = [
					'ScientificName' => $doc [$ar [1]] ['fullScientificName'],
					'Country' => $doc [$ar [1]] ['country'],
					'RecordNo' => $ar [0],
					'Institution' => $doc [$ar [1]] ['institution'],
					'Type' => $doc [$ar [1]] ['sampletype'],
					'cites' =>$cites,
					'collectioncode' =>$doc [$ar [1]] ['collectioncode'],
					'institutioncode' =>$doc [$ar [1]] ['institutioncode']
			];
			$i++;
		}
		Yii::$app->session ['theDocumentsArray'] = $documents;
		return $this->render ( 'cart', [
				'cartContent' => $cartInfo
		] );
	}

	/**
	 * Returns the unitID of the "lowest" sampletype and its index in $doc
	 *
	 * @param unknown $doc
	 * @return
	 *
	 */
	private function getLowest($doc) {
		$order = [
				'DNA',
				'tissue',
				'enviro',
				'specimen',
				'culture',
				'eVoucher',
				'unknown'
		];

		foreach ( $order as $key ) {
			$count = 0;

			foreach ( $doc as $d ) {

				if ($d['sampletype'] == $key) {
					return array (
							$d ['unitID'],
							$count
					);
				}
				$count ++;
			}
		}
	}

	/**
	 * Get the information stored in SOLR for a unit id
	 * @param unknown $unit_id The record to be searched
	 * @return unknown the record.
	 */
	private function getInfo($unitID, $collectioncode, $institutioncode) {
		$config = SOLRQueryManager::getConfigDetails ();
		$query = SOLRQueryManager::createSearchQuery ( $config );

		$unitID = str_replace ( " ", "\ ", $unitID );
		$unitID = str_replace ( "(", "(", $unitID );
		$unitID = str_replace ( ")", ")", $unitID );
		$unitID = str_replace ( ":", ":", $unitID );
		
		$collectioncode = str_replace ( " ", "\ ", $collectioncode );
		$collectioncode = str_replace ( "(", "(", $collectioncode );
		$collectioncode = str_replace ( ")", ")", $collectioncode );
		$collectioncode = str_replace ( ":", ":", $collectioncode );
		
		$institutioncode = str_replace ( " ", "\ ", $institutioncode );
		$institutioncode = str_replace ( "(", "(", $institutioncode );
		$institutioncode = str_replace ( ")", ")", $institutioncode );
		$institutioncode = str_replace ( ":", ":", $institutioncode );
		
		

 		$fq = "{!join from=tripleidstoreid to=tripleidstoreid fromIndex=" . Yii::$app->params ['solrsearchname'] . "}";
		$fq.= "unitID:" . $unitID." AND collectioncode:".$collectioncode. " AND institutioncode:".$institutioncode;
		$raw_response = SOLRQueryManager::fillAndExecuteQuery ( $query, '*:*', $fq, [ ], False ); // while programming: check if null or [] for the parameter after fq
		$doc = $raw_response->getDocuments ();
		return $doc;
	}

	/**
	 * this function generates the csv file containing information about the Dna or tissue samples
	 * which are stored in $documents, which is an array of Solr-reponses
	 * The generated file is named automatically, because it is deleted after the mail was sent,
	 * because the minimum of personal information shoud be stored.
	 *
	 * @param unknown $documents
	 * @param unknown $lowestIndex
	 * @return The genreated filename and an array containing the information
	 * which will be written in the confirmation mails.
	 */
	private function generateCSV($documents, $filename, $forInst) {
		try {
			$hasCites=false;
			$mailArray = [];
 			$mailInfo = array('fullScientificName','familia','country','DNA_ID', 'tissue_ID', 'specimen_ID', 'tripleidstoreid', 'citesStatus');
//			$mailInfo = array('fullScientificName','familia','country','DNA_ID', 'tissue_ID', 'specimen_ID', 'citesStatus');

			$filename = str_replace(",", "", $filename);
			$filename = str_replace(" ", "", $filename);
			$filename = join(DIRECTORY_SEPARATOR,[Yii::$aliases['@mailtmp'],$filename]).rand(0,200).".csv";
			$handle = fopen ( $filename, 'w' );
			$firstLine = array (
					'DNA_ID',
					'DNA_GUID',
					'tissue_ID',
					'tissue_GUID',
					'specimen_ID',
					'specimen_GUID',
					'fullScientificName',
					'familia',
					'ordo',
					'classis',
					'phylum',
					'regnum',
					'continent',
					'country',
					'ocean',
					'locality',
					'longitude',
					'latitude',
					'collectors',
					'collectionDate',
					'collectorNo'
			);
			fwrite ( $handle, implode ( ',', $firstLine ) . "\r\n" );
			foreach ( $documents as $doc ) {
				$lowestIndex = $this->getLowest ( $doc )[1];

				$helperAr = [ ];
				// Gather the hierarchy information for DNA, tissue and specimen
				foreach ( $doc as $d ) {
					if($d['citesStatus']!="N/A")
						$hasCites=true;
					if ($d ['sampletype'] == 'DNA' && ! isset ( $helperAr ['DNA_ID'] )) {
						$helperAr ['DNA_ID'] = $d ['unitID'] . ";" . $d ['collectioncode'] . ";" . $d ['institutioncode'];
						try {
							$helperAr ['DNA_GUID'] = $d ['guid'];
						} catch ( Exception $e ) {
							$helperAr ['DNA_GUID'] = '';
						}
					}
					if ($d ['sampletype'] == 'tissue') {
						$helperAr ['tissue_ID'] = $d ['unitID'] . ";" . $d ['collectioncode'] . ";" . $d ['institutioncode'];
						try {
							$helperAr ['tissue_GUID'] = $d ['guid'];
						} catch ( Exception $e ) {
							$helperAr ['tissue_GUID'] = '';
						}
					}
					if ($d ['sampletype'] == 'specimen'||$d ['sampletype'] == 'culture') {
						$helperAr ['specimen_ID'] = $d ['unitID'] . ";" . $d ['collectioncode'] . ";" . $d ['institutioncode'];
						try {
							$helperAr ['specimen_GUID'] = $d ['guid'];
						} catch ( Exception $e ) {
							$helperAr ['specimen_GUID'] = '';
						}
					}
				}
				// fill the missing fields with an empty string
				foreach ( array (
						'DNA_ID',
						'tissue_ID',
						'specimen_ID',
						'DNA_GUID',
						'tissue_GUID',
						'specimen_GUID'
				) as $key ) {
					if (! isset ( $helperAr [$key] )) {
						$helperAr [$key] = '';
					}
				}
				// Gather all the missing information from the lowest sample =>DNA (lowest), tissue, specimen
				$array = $doc [$lowestIndex];
				foreach ( array (
						'fullScientificName',
						'familia',
						'ordo',
						'classis',
						'phylum',
						'regnum',
						'country',
						'locality',
						'collectors'
				) as $key ) {
					try {
						$helperAr [$key] = $array [$key];
					} catch ( Exception $e ) {
						$helperAr [$key] = '';
					}
				}
				try {
					$coord = $array ['coordinates'] [0];
					if (isset ( $coord )) {
						$coord = explode ( ",", $coord );
						$helperAr ['longitude'] = $coord [0];
						$helperAr ['latitude'] = $coord [1];
					} else {
						$helperAr ['longitude'] = '';
						$helperAr ['latitude'] = '';
					}
				} catch ( Exception $e ) {
					$helperAr ['longitude'] = '';
					$helperAr ['latitude'] = '';
				}
				// $helperAr['collectionDate']= $array['gatheringyear'];//TODO
				$helperAr ['collectionDate'] = "";
				$helperAr ['collectorNo'] = $array ['collectornumber'];
				$helperAr ['continent'] = $array ['continent'] [0];
				$helperAr ['ocean'] = $array ['ocean'] [0];
 				$helperAr ['tripleidstoreid'] =$array ['tripleidstoreid'];
				$helperAr['citesStatus'] =$array['citesStatus'];

				// write the line to the file. Replace all existing commas by semicolons
				$line = '';
				foreach ( $firstLine as $value ) {
					$rep = str_replace ( ",", ";", $helperAr [$value] );
					$line .= $rep . ',';
				}
				fwrite ( $handle, $line . "\r\n" );

				foreach($mailInfo as $item){
					if(!$helperAr['DNA_ID']==''){
					$mailArray[$helperAr['DNA_ID']][$item] = $helperAr[$item];
					}
					elseif(!$helperAr['tissue_ID']==''){
						$mailArray[$helperAr['tissue_ID']][$item] = $helperAr[$item];
					}
					elseif(!$helperAr['specimen_ID']==''){
						$mailArray[$helperAr['specimen_ID']][$item] = $helperAr[$item];
					}
				}
				
			}
			if($hasCites && $forInst)
				fwrite ( $handle, "This pre-order contains request for CITES material. Please check carefully whether the customer is allowed to receive this material.\n" );
			fclose ( $handle );
		} catch ( Exception $e ) {
			// TODO
		}
		return [$filename,$mailArray,'cites'=>$hasCites];
	}

	/**
	 * This function renders a page containing an ActiveForm where you can enter your cites code.
	 * This page is rendered in a Modal window.
	 * @return \yii\web\Response|Ambigous <string, string>
	 */
	public function actionCheckout() {
		$this->layout = 'form';
		$model = new CheckoutForm ();
		if ($model->load ( Yii::$app->request->post () ) && $model->validate ()) {
			Yii::$app->user->identity->saveNewUserData ( $_POST ['CheckoutForm'] );
			$this->layout = 'main';
			return $this->redirect ( 'overview' );
		}
		return $this->render ( 'checkout', [
				'model' => $model
		] );
	}

	/**
	 * Deletes all non-ordered samples (for the current user) from the shopping cart.
	 * @return \yii\web\Response
	 */
	public function actionDelete() {
		DBInterface::emtpyShoppingCart ( Yii::$app->user->identity->id );
		return $this->goHome ();
	}

	/**
	 * This is the action which actually performs the checkout!
	 */
	public function actionThankyou() {
		$files = [ ];
		if(empty(Yii::$app->session ['theDocumentsArray'])){
			return $this->goHome();
		}
		DBInterface::emtpyShoppingCart ( Yii::$app->user->identity->id );
		$support = \Yii::$app->params ['supportEmail'];
		$documents = Yii::$app->session ['theDocumentsArray'];
		$user = Yii::$app->user->identity;

		// send the checkout mails to the institutions
		$institution = $this->getAllDocsForAllInstitutions ( $documents );
		$contactPeople = [];
		$instMail = 'institutionConfirmation';
		foreach ($institution as $key =>$inst){
			$tripleidstoreid = $inst[0][0]['tripleidstoreid'];
			$contactPerson = DBInterface::getMail($tripleidstoreid)[0];
			array_push($contactPeople , $contactPerson);
			$ar2 = $this->generateCSV($inst, 'order'.$key, true);
			$files = array($ar2[0]);
			$cites=$ar2['cites'];
			//Get the comment a user made for this institution
			$comment = Yii::$app->session['CommentArray']['comments'][$key];
			$numSent = $this->sendMailWithFiles($contactPerson['email'], 
					$support, 
					$instMail, 
					'[GGBN] Sample request', 
					$files, 
					$comment, 
					$user, 
					$contactPerson, 
					$ar2[1],
					$cites
					);
			if(!$numSent){
				Yii::$app->mailer->compose ()
				->setFrom (Yii::$app->params ['noreplyMail'] )
				->setTo ( Yii::$app->params ['adminMail'] )
				->setSubject ( 'Order Mail not sent' )
				->setTextBody ( "The mail for the order to ".$contactPerson['email']." was not sent." )
				->send ();
				
			}
			//write the information into the user_shopping_statistics database table.
			$this->writeStats($contactPerson['parentInstitutionID'], $ar2[1]);
		}

		// send the confirmation mail to the users
		//TODO: add MTA path.
		$ar1 = $this->generateCSV ( $documents, 'yourorder', false );
		// $MTA = path
		$files = [$ar1[0]];
		$mail = 'customerConfirmation';
		$numSent = $this->sendMailWithFiles ( $user->email, 
				$support, 
				$mail, 
				'[GGBN] Your sample order', 
				$files, 
				null, 
				$user, 
				$contactPeople, 
				$ar1[1],
				false);
		if(!$numSent){
			Yii::$app->mailer->compose ()
			->setFrom (Yii::$app->params ['noreplyMail'] )
			->setTo ( Yii::$app->params ['adminMail'] )
			->setSubject ( 'Order Mail not sent to customer ' )
			->setTextBody ( "The mail for the order to ".$user->email." was not sent." )
			->send ();
		}
		//cleanup actions
		Yii::$app->session->remove('theDocumentsArray');
		Yii::$app->session->remove('CommentArray');
		$this->cleanUpDir(Yii::$aliases['@mailtmp'],$files);
		return $this->render('thankyou');
	}


	/**
	 * Sends the confirmation emails.
	 * @param unknown $to destination email
	 * @param unknown $from sender email
	 * @param unknown $mail the mail template
	 * @param unknown $subject the subject of the mail
	 * @param unknown $files the files to join
	 * @param unknown $comment the comment the user made for this institution
	 * @param unknown $user the identity object
	 * @param unknown $contactPerson an array containing all the necessary information on the contact person (name, email, Institution)
	 * @param unknown $infoInMailArray The information on the ordered samples
	 */
	private function sendMailWithFiles($to, $from, $mail, $subject, $files, $comment, $user, $contactPerson, $infoInMailArray, $cites) {
		$mail = \Yii::$app->mailer->compose ( [
				'html' => $mail . '-html',
				//'text' => $mail . '-text'
		], [
				'user' => Yii::$app->user->identity,
				'comment' =>$comment,
				'contactPerson'=>$contactPerson,
				'information' =>$infoInMailArray,
				'citesStatus'=>$cites
		] )->setFrom (Yii::$app->params ['noreplyMail'])
		->setTo ( $to )->setSubject ( $subject );
		foreach ( $files as $file ) {
			$mail->attach ( $file );
		}
		return $mail->send ();
	}

	/**
	 * creates an array, that contains for every insitution all ordered samples, (the information is
	 * stored in the document format)
	 * @param unknown $documents
	 * @return multitype:multitype:unknown
	 */
	private function getAllDocsForAllInstitutions($documents) {
		$resultsArray = [ ];
		//var_dump($documents);
		foreach ( $documents as $d ) {
				if (array_key_exists ( strtoupper($d[0] ['institution']), $resultsArray )) {
					array_push ( $resultsArray [strtoupper($d[0] ['institution'])],$d);
				} else {
					$resultsArray [strtoupper($d[0] ['institution'])] = array($d);
				}
		}
		//var_dump($resultsArray);
		return $resultsArray;
	}

	/**
	 * Return the last overview before actual ordering the samples.
	 * @return Ambigous <string, string>|\yii\web\Response
	 */
	public function actionOverview() {
		$model = new CheckoutForm();
	if(empty(Yii::$app->session ['theDocumentsArray'])){
			return $this->render('cart');
		}
		if($model->load ( Yii::$app->request->post () ) && $model->validate ()){
			Yii::$app->session['CommentArray']=$_POST['CheckoutForm'];
			return $this->redirect('thankyou');
		}
		$docs = $this->getAllDocsForAllInstitutions ( Yii::$app->session ['theDocumentsArray'] );
		//var_dump($docs);
		$arr = [ ];
		foreach ( $docs as $key => $value ) {
			$arr [$key] = [ ];
			foreach($value as $val){
			$ind = $this->getLowest($val)[1];
			$logo = $this->getLogo ( $val [$ind] ['tripleidstoreid'] );
			array_push ( $arr [$key], array (
							'unitID' => $val [$ind]  ['unitID'],
							'fullScientificName' => $val [$ind]  ['fullScientificName'],
							'sampletype' => $val [$ind]  ['sampletype'],
							'logo' => $logo
					) );
				}
			}
		return $this->render ( 'overview', [
				'info' => $arr,
				'model' => $model
		] );
	}

	/**
	 * Deletes one sample from the shopping cart.
	 * @param unknown $unit_id The unit_id of the sample to be deleted.
	 * @return \yii\web\Response
	 */
	public function actionDeleteone($unit_id,$collection_code,$institution_code) {
		DBInterface::deleteFromShoppingCart ( $unit_id, $collection_code,$institution_code, Yii::$app->user->id );
		return $this->redirect ( 'cart' );
	}

	/**
	 * Gets the logo of an institution given a tripleidstoreid
	 * @param unknown $tripleidstoreid
	 * @return unknown
	 */
	private function getLogo($tripleidstoreid) {
		$query = DBInterface::getLogo ( $tripleidstoreid );
		return $query ['logoURL'];
	}

	/**
	 * Function responsible for filling the shopping_statistics db table.
	 * It counts the different sampletypes.
	 * @param unknown $id The parentInstitutionID
	 * @param unknown $mailArray the information
	 */
	private function writeStats($id, $mailArray){
		$dna = 0;
		$tissue = 0;
		$dna_request = 0;
		//var_dump($mailArray);
		foreach ($mailArray as $ma){
			if(!empty($ma['DNA_ID'])){
				$dna++;
			}
			elseif(!empty($ma['tissue_ID'])){
				$tissue++;
			}
			elseif (!empty($ma['specimen_ID'])){
				$dna_request++;
			}
		}
		DBInterface::stats($id, array($dna, $tissue, $dna_request));
	}

	/**
	 * removes all created csv files from the mailTmp dir. (See aliases)
	 * @param unknown $dir
	 */
	private function cleanUpDir($dir,$todel){
		$todelbases=[];
		foreach ($todel as $t)
			$todelbases[]=basename($t);
// 		Yii::info("look for cleanup ".implode(", ", $todelbases));
		$files = glob($dir."\\*"); // get all file names
		foreach($files as $file){ // iterate files
// 			Yii::info("wants to delete file ".basename($file));
			if(is_file($file) && in_array(basename($file), $todelbases))
				unlink($file); // delete file
		}
	}


}