<?php

namespace Edi;

require_once (__DIR__.'/section.php');

class SectionInfo
{
	var $schema;
	var $parentInfo;
	var $section;
}

class Message
{
	var $section;
	
	static function loadSchema ($schemaName)
	{
		$ediSchemaStr = file_get_contents (__DIR__."/$schemaName.json", TRUE);

		if ($ediSchemaStr !== FALSE)
			return json_decode ($ediSchemaStr, TRUE);
			
		return NULL;
	}

	static function isEdiString (&$string)
	{
		return substr ($string, 0, 4) == 'UNB+';
	}

	function parse (&$string, &$schema = NULL)
	{
		global $delimiters;

		if (!self::isEdiString ($string))
			throw new \Exception ('Not an EDI string.');

		$pos = 0;
		$error = FALSE;
		$endTag = NULL;
		$firstLoop = TRUE;
		$newSection = TRUE;

		$info = new SectionInfo ();
		$info->schema = $schema;
		$info->parentInfo = NULL;
		$info->section = NULL;
		$topInfo = $info;

		try {
		while (TRUE)
		{
			$segment = $this->parseSegment ($string, $pos);

			if (!$segment && (!$endTag || !$info))
				break;
			
			if (!$segment || ($segment && !$info))
				throw new \Exception ();

			if ($firstLoop)
			{			
				if ($segment->name != $info->schema['mainTag'])
					throw new \Exception ();
			}
			else
			{
				for ($i = $info; $i; $i = $i->parentInfo)
				if (isset ($i->schema['childs'][$segment->name]))
				{
					$info = new SectionInfo ();
					$info->schema = $i->schema['childs'][$segment->name];
					$info->parentInfo = $i;
					$newSection = TRUE;
					break;
				}
			}

			if ($newSection)
			{
				$section = new Section ();
				$section->name = $segment->name;
				$info->section = $section;
				
				if ($info->parentInfo)
				{
					$section->parent = $info->parentInfo->section;
					$section->parent->childs[$segment->name][] = $section;
				}

				if (isset ($info->schema['endTag']))
					$endTag = $info;
					
				$newSection = FALSE;
			}
		
			if ($endTag && $endTag->schema['endTag'] == $segment->name)
			{
				$endTag->section->segments[] = $segment;
				$info = $endTag->parentInfo;
				
				for ($i = $info; $i; $i = $i->parentInfo)
				if (isset ($i->schema['endTag']))
				{
					$endTag = $i;
					break;
				}
			}
			else
				$info->section->segments[] = $segment;
			
			$firstLoop = FALSE;
		}}
		catch (\Exception $e)
		{
			throw new \Exception (sprintf ('Parse error, something is wrong near "%s"',
				substr ($string, $pos, 10)));
		}

		$this->section = $topInfo->section;
	}

	function parseSegment (&$string, &$pos)
	{
		$empty = TRUE;
		$values = [];
	
		while (TRUE)
		{
			if (!isset ($string{$pos}))
				return NULL;
		
			if (in_array ($string{$pos}, ['+', ':', '\'']))
			{
				if (!$empty)
				{
					$values[] =
						trim (substr ($string, $start, $pos - $start));
					$empty = TRUE;
				}
			}
			elseif ($empty)
			{
				$start = $pos;
				$empty = FALSE;
			}
			
			if ($string{$pos} === '\'')
				break;

			$pos++;
		}
		
		$pos++;
	
		$segment = new Segment ();
		$segment->name = $values[0];
		$segment->values = $values;
		return $segment;
	}
}