<?php
require_once(__DIR__ . '/parser1.inc.php');
require_once(__DIR__ . '/parser2.inc.php');

define('MTG_PARSER_TYPE_1', "1.0");
define('MTG_PARSER_TYPE_2', "2.0a");

interface mtgIMetaInfoParser
{
  function parse(mtgMetaInfo $meta, string $file);
}

class mtgMetaParsedModule implements mtgScope
{
  public string $file;
  public $units = array();
  public $includes = array();

  function __construct(string $file)
  {
    $this->file = $file;
  }

  function addUnit(mtgMetaInfoUnit $unit)
  {
    $this->units[$unit->object->getMetaId()] = $unit;
  }

  function findSymbol($name)
  {
    $unit = $this->findUnit($name);
    if(!$unit)
      return null;
    return $unit->object;
  }

  function findUnit($id)
  {
    if(isset($this->units[$id]))
      return $this->units[$id];

    foreach($this->includes as $include)
    {
      if(isset($include->units[$id]))
        return $include->units[$id];
    }

    return null;
  }

  function addInclude(mtgMetaParsedModule $include)
  {
    $this->includes[] = $include;
  }
}

function mtg_parse_meta(array $meta_srcs, $valid_tokens = null, $inc_path = null, $version = null)
{
  if($inc_path === null)
  {
    //let's autodetect include path
    $inc_path = array();
    foreach($meta_srcs as $src)
    {
      if(is_dir($src))
        $inc_path[] = $src;
      else if(is_file($src))
        $inc_path[] = dirname($src);
    }
  }

  $meta_parser = null;

  if($version === null || $version === MTG_PARSER_TYPE_1)
    $meta_parser = new mtgMetaInfoParser(
        array(
          'include_path' => $inc_path, 
          'valid_tokens' => $valid_tokens
        )
      );
  else if($version === MTG_PARSER_TYPE_2)
    $meta_parser = new mtgMetaInfoParser2(
        array(
          'include_path' => $inc_path, 
          'valid_tokens' => $valid_tokens
        )
      );
  else
    throw new Exception("Unknown meta parser version: $version");

  $meta = new mtgMetaInfo();

  foreach($meta_srcs as $src)
    mtg_load_meta($meta, $meta_parser, $src);

  $meta->validate();

  mtgTypeRef::checkAllResolved();

  return $meta;
}

function mtg_load_meta(
  mtgMetaInfo $meta, mtgIMetaInfoParser $meta_parser, 
  string $dir_or_file, string $extension = '.meta'
)
{
  $files = mtg_resolve_files($dir_or_file, $extension);
  foreach($files as $file)
    $meta_parser->parse($meta, $file);
}

function mtg_resolve_files(string $dir_or_file, string $extension = '.meta') : array
{
  $files = array();
  if(is_dir($dir_or_file))
    $files = mtg_find_meta_files($dir_or_file, $extension);
  else if(is_file($dir_or_file))
    $files[] = $dir_or_file;
  else
    throw new Exception("Bad meta source '$dir_or_file'");
  return $files;
}

function mtg_find_meta_files($dir, $extension = '.meta')
{
  $items = scandir($dir);
  if($items === false)
    throw new Exception("Directory '$dir' is invalid");

  $files = array();
  foreach($items as $item)
  {
    if($item[0] == '.')
      continue;

    if(strpos($item, $extension) !== (strlen($item)-strlen($extension)))
      continue;

    $file = $dir . '/' . $item;
    if(is_file($file) && !is_dir($file))
      $files[] = $file;
  }
  return $files;
}