<?php

require_once (__DIR__.'/lib/method.php');
require_once (__DIR__.'/lib/message.php');

use Vn\Lib\Type;

class Load extends Edi\Method
{
	function ediRun ($db)
	{
		$this->ediSchema = Edi\Message::loadSchema ('CLOCKT');
		
		if (!$this->ediSchema)
			throw new Exception ('Can not load EDI schema.');
		
		$this->params = $db->query (
			'SELECT code, name, subname, position, type, required FROM param');

		$inbox = imap_search ($this->imap, 'ALL');

		if ($inbox)
		{
			foreach ($inbox as $msg)
				$this->loadMail ($db, $msg);

			$inboxCount = count ($inbox);

			if ($inboxCount > 0)
				echo "Total $inboxCount messages readed\n";
		}
	}
	
	function loadMail ($db, $msg)
	{
		$imap = $this->imap;
	
		// Gets EKT messages from email

		$msgStructure = imap_fetchstructure ($imap, $msg);
		$result = [];
		
		// Gets the mail sender and Message-ID

		$header = imap_headerinfo ($imap, $msg);
		$from = $header->from;
		$mailId = trim ($header->message_id, '<>');

		if ($from && count ($from) > 0)
			$sender = $from[0]->mailbox .'@'. $from[0]->host;
		else
			$sender = NULL;
		
		// Searches the EDI message on mail parts

		$matchTypes = [TYPEAPPLICATION, TYPETEXT];
		$this->imapFindParts ($msgStructure, $matchTypes, [], $result);

		$count = 0;
		$error = NULL;

		foreach ($result as $msgSection)
		try
		{
			$part = imap_bodystruct ($imap, $msg, $msgSection);
			$ediString = imap_fetchbody ($imap, $msg, $msgSection);

			switch ($part->encoding)
			{
				case ENCBASE64:
					$ediString = imap_base64 ($ediString);
					break;
				case ENCQUOTEDPRINTABLE:
					$ediString = imap_qprint ($ediString);
					break;
			}

			if (!Edi\Message::isEdiString ($ediString))
				continue;
	
			// Creates the EDI object and loads its exchanges

			$ediMessage = new Edi\Message ();
			$ediMessage->parse ($ediString, $this->ediSchema);

			$db->query ('START TRANSACTION');
			$db->query ('CALL messageNew (#mailId, #sender, @message)',
			[
				'mailId' => $mailId,
				'sender' => $sender
			]);
	
			$unb = $ediMessage->section;
			$unhs = $unb->childs['UNH'];
	
			foreach ($unhs as $unh)
			foreach ($lins = $unh->childs['LIN'] as $lin)
			{
				$ediValues = [];
	
				// Gets the exchange params

				$this->params->data_seek (0);

				while ($row = $this->params->fetch_assoc ())
				{
					switch ($row['type'])
					{
						case 'INTEGER':
							$type = Type::INTEGER;
							break;
						case 'DOUBLE':
							$type = Type::DOUBLE;
							break;
						case 'DATE':
							$type = Type::DATE;
							break;
						case 'TIME':
							$type = Type::TIME;
							break;
						default:
							$type = Type::STRING;
					}
	
					$value = $lin->getValue (
						$row['name'], $row['position'], $type, $row['subname']);

					if (!isset ($value) && $row['required'])
						throw new Exception ('Missing required parameter: '. $row['code']);

					$ediValues[$row['code']] = $value;
				}

				// Gets the exchange features

				$res = $db->query (
					'SELECT presentation_order, feature 
						FROM item_feature
						WHERE item_id = #ref
							AND entry_date <= CURDATE()
							AND (expiry_date IS NULL OR expiry_date >= CURDATE())
						GROUP BY presentation_order'
					,$ediValues
				);

				if ($res)
				while ($row = $res->fetch_assoc ())
				{
					$value = $lin->getValue ('IMD', 2, Type::INTEGER, $row['feature']);	
					$ediValues['s'.$row['presentation_order']] = $value;
				}
				else
					throw new Exception ('Can\'t get the item features.');
		
				for ($i = 1; $i <= 6; $i++)
				if (!isset ($ediValues['s'.$i]))
					$ediValues['s'.$i] = NULL;

				// Adds the exchange to the Database

				$res = $db->queryFromFile (__DIR__.'/sql/batch-add', $ediValues);

				if (!$res)
					throw new Exception ('Failed to insert the line.');

				$count++;
			}

			$db->query ('COMMIT');
		}
		catch (Exception $e)
		{
			$db->query ('ROLLBACK');
			$error = $e->getMessage ();
			break;
		}
	
		if (!$error && $count == 0)
			$error = 'EDI messages not found.';

		// Logs information of realized operations

		if (!$error)
		{
			$folder = $this->imapConf['success_folder'];
			echo "Mail loaded with $count lines.\n";
		}
		else
		{
			$folder = $this->imapConf['error_folder'];
			echo "Mail error: $error\n";
		}

		// Moves the mail to another folder

		$folder = sprintf ('%s', $folder);

		if (!imap_mail_move ($imap, $msg, $folder))
			error_log ('Can\'t move message to %s: %s'
				,$folder
				,imap_last_error ()
			);
	}
	
	function imapFindParts (&$part, &$matchTypes, $section, &$result)
	{
		if (in_array ($part->type, $matchTypes))
		{
			if (count ($section) > 0)
				$result[] = implode ('.', $section);
			else
				$result[] = '1';
		}
		elseif ($part->type == TYPEMULTIPART)
		foreach ($part->parts as $i => $subpart)
		{
			array_push ($section, $i + 1);
			$this->imapFindParts ($subpart, $matchTypes, $section, $result);
			array_pop ($section);
		}
	}
}