using Godot;
using System.Collections.Generic;

namespace Rokojori
{
  public class SceneFile
  {
    public static SceneFileEntry Create( string type, string line )
    {
      var entry = new SceneFileEntry();
      entry.type = type;
      entry.line = line;

      entry.Parse();
      return entry;
    }

    public static SceneFileEntry Seperator()
    {
      return Create( SceneFileLinesLexer.SeperatorMatcher.type, "" );
    }

    // Parsed lines
    public List<SceneFileEntry> entries = new List<SceneFileEntry>();

    // Combined objects of parsed lines
    public List<SceneFileObject> objects = new List<SceneFileObject>();

    
    public GDSceneSFO gdScene;
    public NodeSFO rootNode;
    
    // Nodes of the scene
    public List<NodeSFO> nodes = new List<NodeSFO>();

    // NodePath -> Node
    public Dictionary<string,NodeSFO> nodePathMap = new Dictionary<string, NodeSFO>();
    
    // External Resources
    public List<ExtResourceSFO> extResources = new List<ExtResourceSFO>();

    // Built-In Resources
    public List<SubResourceSFO> subResources = new List<SubResourceSFO>();

    public SceneFile GetSerializableJSONVersion()
    {
      var file = new SceneFile();
      file.entries = entries;
      
      return file;
    }

    public void CreateObjects()
    {
      SceneFileObject lastSFO = null;

      entries.ForEach(
        ( e )=>
        {
          if ( ! e.hasHeader )
          {
            lastSFO.AddData( e );
            return;
          }

          var sfo = SceneFileObjectFactory.Create( e );

          if ( sfo == null )
          {
            return;
          }

          lastSFO = sfo;

          if ( sfo is GDSceneSFO )
          {
            gdScene = (GDSceneSFO) sfo;
          }
          else if ( sfo is NodeSFO )
          {
            var node = (NodeSFO) sfo;
            nodes.Add( node );

            if ( node.elementPath == "." )
            {
              rootNode = node;
            }

            nodePathMap[ node.elementPath ] = node;

            // RJLog.Log( "'" + node.elementPath + "'", node.name.value );
            
          }
          else if ( sfo is ExtResourceSFO )
          {
            extResources.Add( (ExtResourceSFO) sfo );
          }
          else if ( sfo is SubResourceSFO )
          {
            subResources.Add( (SubResourceSFO) sfo );
          }

          objects.Add( sfo ); 
        }
      );

      nodes.ForEach( 
        ( n )=>
        {
          n.ResolveParent( nodePathMap, rootNode );
        }
      );
    }
  }
}