//public GraphTriangulator(GraphGenerator generator, NavMeshTemplateCreation template) {
        //    var volumes = generator.getVolumes;
        //    var nodes = generator.getNodes;

        //    //layer, hash
        //    Dictionary<int, Dictionary<int, List<NodeAbstract>>> dicNodes = new Dictionary<int, Dictionary<int, List<NodeAbstract>>>();
        //    Dictionary<int, Dictionary<int, List<EdgeAbstract>>> dicEdges = new Dictionary<int, Dictionary<int, List<EdgeAbstract>>>();
        //    Dictionary<int, Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>> dicValues = new Dictionary<int, Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>>();

        //    foreach (var volume in volumes) {
        //        dicNodes.Add(volume.id, new Dictionary<int, List<NodeAbstract>>());
        //        dicEdges.Add(volume.id, new Dictionary<int, List<EdgeAbstract>>());
        //        dicValues.Add(volume.id, new Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>());

        //        //some hardcoded stuff
        //        foreach (var a in volume.containsAreas) {
        //            int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable);
        //            int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable);

        //            dicNodes[volume.id].Add(crouchHash, new List<NodeAbstract>());
        //            dicEdges[volume.id].Add(crouchHash, new List<EdgeAbstract>());
        //            dicValues[volume.id].Add(crouchHash, new Dictionary<NodeAbstract, TriangulatorNodeData>());

        //            dicNodes[volume.id].Add(walkHash, new List<NodeAbstract>());
        //            dicEdges[volume.id].Add(walkHash, new List<EdgeAbstract>());
        //            dicValues[volume.id].Add(walkHash, new Dictionary<NodeAbstract, TriangulatorNodeData>());
        //        }
        //    }

        //    foreach (var first in nodes) {
        //        foreach (var pair in first.getData) {
        //            int volume = pair.Key.x;
        //            int hash = pair.Key.y;

        //            dicNodes[volume][hash].Add(first);
        //            dicEdges[volume][hash].Add(first[volume, hash]);

        //            NodeTemp middle = first.GetNode(volume, hash);
        //            NodeTemp last = middle.GetNode(volume, hash);

        //            float cross = SomeMath.V2Cross(
        //                last.x - middle.x, last.z - middle.z,
        //                first.x - middle.x, first.z - middle.z);

        //            if (cross < 0) {
        //                Vector2 directionLast = new Vector2(last.x - middle.x, last.z - middle.z).normalized;
        //                Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized;
        //                dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1));
        //            }
        //            else
        //                dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero));
        //        }
        //    }

        //    foreach (var volume in volumes) {
        //        foreach (var a in volume.containsAreas) {
        //            int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable);
        //            data.Add(new TriangulatorDataSet(
        //                template,
        //                dicNodes[volume.id][crouchHash],
        //                dicEdges[volume.id][crouchHash],
        //                dicValues[volume.id][crouchHash],
        //                volume.id, a, Passability.Crouchable));


        //            int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable);
        //            data.Add(new TriangulatorDataSet(
        //                template,
        //                dicNodes[volume.id][walkHash],
        //                dicEdges[volume.id][walkHash],
        //                dicValues[volume.id][walkHash],
        //                volume.id, a, Passability.Walkable));
        //        }
        //    }

        //    //data.RemoveAll(x => x.nodes.Count == 0);
        //}

        public GraphTriangulator(GraphGeneratorNew generator, NavMeshTemplateCreation template)
        {
            int maxLayers = generator.volumeContainer.layersCount;

            //var volumes = generator.dataLayers;
            var nodes = generator.getNodes;

            //DataLayer[] dataLayers = generator.dataLayers;
            //int dataLayersLength = dataLayers.Length;

            profiler = template.profiler;



            //layer, hash
            Dictionary <int, List <NodeAbstract> >[] dicNodes = new Dictionary <int, List <NodeAbstract> > [maxLayers];
            Dictionary <int, List <EdgeAbstract> >[] dicEdges = new Dictionary <int, List <EdgeAbstract> > [maxLayers];
            Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >[] dicValues = new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> > [maxLayers];

            for (int id = 0; id < maxLayers; id++)
            {
                dicNodes[id]  = new Dictionary <int, List <NodeAbstract> >();
                dicEdges[id]  = new Dictionary <int, List <EdgeAbstract> >();
                dicValues[id] = new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >();

                //DataLayer layer = dataLayers[id];

                //some hardcoded stuff
                //foreach (var hash in layer.allAreaHashes) {
                //    dicNodes[id].Add(hash, new List<NodeAbstract>());
                //    dicEdges[id].Add(hash, new List<EdgeAbstract>());
                //    dicValues[id].Add(hash, new Dictionary<NodeAbstract, TriangulatorNodeData>());
                //}
            }
            if (profiler != null)
            {
                profiler.AddLog("start preparing data in GraphTriangulator");
            }
            foreach (var first in nodes)
            {
                foreach (var pair in first.getData)
                {
                    int layer = pair.Key.x;
                    int hash  = pair.Key.y;

                    var curDicNodes  = dicNodes[layer];
                    var curDicEdges  = dicEdges[layer];
                    var curDicValues = dicValues[layer];


                    if (curDicNodes.ContainsKey(hash) == false)
                    {
                        curDicNodes.Add(hash, new List <NodeAbstract>());
                        curDicEdges.Add(hash, new List <EdgeAbstract>());
                        curDicValues.Add(hash, new Dictionary <NodeAbstract, TriangulatorNodeData>());
                    }

                    curDicNodes[hash].Add(first);
                    curDicEdges[hash].Add(first[layer, hash]);

                    NodeTemp middle = first.GetNode(layer, hash);
                    NodeTemp last   = middle.GetNode(layer, hash);

                    float cross = SomeMath.V2Cross(
                        last.x - middle.x, last.z - middle.z,
                        first.x - middle.x, first.z - middle.z);

                    if (cross < 0)
                    {
                        Vector2 directionLast  = new Vector2(last.x - middle.x, last.z - middle.z).normalized;
                        Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized;
                        curDicValues[hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1));
                    }
                    else
                    {
                        curDicValues[hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero));
                    }
                }
            }


            for (int id = 0; id < maxLayers; id++)
            {
                foreach (var hash in dicNodes[id].Keys)
                {
                    Area        area;
                    Passability pass;
                    template.hashData.GetAreaByHash((short)hash, out area, out pass);

                    data.Add(new TriangulatorDataSet(
                                 template,
                                 dicNodes[id][hash],
                                 dicEdges[id][hash],
                                 dicValues[id][hash],
                                 id, area, pass));
                }
            }
            if (profiler != null)
            {
                profiler.AddLog("end preparing data in GraphTriangulator");
            }
            //data.RemoveAll(x => x.nodes.Count == 0);
        }
        public void GenerateGraph()
        {
            if (profiler != null)
            {
                profiler.AddLog("start thread", Color.green);
                profiler.StartThreadStuff();
            }

            if (stop)
            {
                if (profiler != null)
                {
                    profiler.Abort();
                }
                return;
            }

            //VolumeContainer volumes = new VolumeContainer(this);

            ////collecting terrain
            //if (profiler != null) profiler.AddLog("start collecting volumes", Color.green);
            //if (_terrainCollector.collectedCount > 0) {
            //    if (profiler != null) profiler.AddLogFormat("collecting terrains. Count: {0}", Color.green, _terrainCollector.collectedCount);
            //    _terrainCollector.Collect(volumes);
            //    if (profiler != null) profiler.AddLog("terrain collected");
            //}
            //else {
            //    if (profiler != null) profiler.AddLog("No terrain to collect", Color.green);
            //}

            //if (stop) {
            //    if (profiler != null) profiler.Abort();
            //    return;
            //}



            //switch (PathFinder.colliderCollectorType) {
            //    case ColliderCollectorType.CPU:
            //        shapeCollectorCPU.Collect(volumes);
            //        break;
            //    case ColliderCollectorType.ComputeShader:
            //        //collecting primitives
            //        if (_primitivesCollector.collectedCount > 0) {
            //            if (profiler != null) profiler.AddLogFormat("collecting primitives. Count: {0}", Color.green, _primitivesCollector.collectedCount);
            //            _primitivesCollector.profiler = profiler;
            //            _primitivesCollector.Collect(volumes);
            //            if (profiler != null) profiler.AddLog("primitives collected");
            //        }
            //        else {
            //            if (profiler != null) profiler.AddLog("No primitives to collect", Color.green);
            //        }
            //        break;
            //}


            colliderCollector.Collect(); //also apply modifyers

            VolumeContainerNew volume = new VolumeContainerNew(this);

            volume.AddGenericColliders(colliderCollector.shapeCollectorResult);
            volume.DoStuff();

            GraphGeneratorNew generator = new GraphGeneratorNew(volume, this);

            graph = generator.MakeGraph();
            //GraphGenerator generator = new GraphGenerator(volumes, this);
            //graph = generator.MakeGraph();

            //if (stop) {
            //    if (profiler != null) profiler.Abort();
            //    return;
            //}

            ////process collected volumes. remove intersections, reduce volume count, generate connections, flags, etc
            ////best place to modify information about world or add flags
            //if (profiler != null) profiler.AddLog("volumes container start doing stuff");
            //volumes.DoStuff();
            //if (profiler != null) profiler.AddLog("volumes container end doing stuff");

            //if (stop) {
            //    if (profiler != null) profiler.Abort();
            //    return;
            //}

            //if (profiler != null) profiler.AddLog("graph generator start doing stuff", Color.green);
            //GraphGenerator generator = new GraphGenerator(volumes, this);
            //graph = generator.MakeGraph();
            //if (profiler != null) profiler.AddLog("graph generator end making graph");

            //if (stop) {
            //    if (profiler != null) profiler.Abort();
            //    return;
            //}

            //if (profiler != null) profiler.AddLog("Return all remaining volumes to object pool");
            //volumes.ReturnAllVolumesToObjectPool();

            //graph = new Graph();

            if (profiler != null)
            {
                profiler.AddLog("end thread", Color.green);
                profiler.EndThreadStuff();
                profiler.EndProfile();
                profiler.DebugLog(ProfilderLogMode.log);
            }

            //Graph graph = new Graph(chunk, properties);
            if (callbackAfterGraphGeneration != null)
            {
                callbackAfterGraphGeneration.Invoke(this);
            }
        }