<?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);
			}
	}
}