public MazeNode(Point2D position, MazeSpace Room, MazeWall Door)
            : base()
        {
            this.position = position;
            this.Room = Room;
            this.Door = Door;
            if (this.Door != null)
                this.MazeGraphNodeType = MazeNodeType.GateNode;
            else
                this.MazeGraphNodeType = MazeNodeType.SpaceNode;

            incommingGraphArcs = new ArrayList();
            outgoingGraphArcs = new ArrayList();
        }
        public void LoadAll(String filename)
        {
            JToken tempJObject;
            StreamReader reader = File.OpenText(filename);
            JObject o = (JObject)JToken.ReadFrom(new JsonTextReader(reader));

            if (o.TryGetValue("name", out tempJObject))
                worldName =  o.GetValue("name").ToString();

            if (o.TryGetValue("timeout", out tempJObject))
                iWorldTimeout = (int)o.GetValue("timeout");

            mazeWalls = new ArrayList();
            Hashtable mazeWallsById = new Hashtable();
            mazeRobots = new ArrayList();
            mazeVictims = new ArrayList();

            mazeSpaces = new ArrayList();
            Hashtable mazeSpacesById = new Hashtable();
            mazeGraph = new MazeGraph();

            mazeNodeNodes = new ArrayList();
            mazeSpaceNode = new ArrayList();
            mazeSpaceRobots = new ArrayList();

            foreach (JObject jObject in o.GetValue("walls").Children())
            {
                MazeWall mazeWall = new MazeWall(
                    new Point2D((double)((JObject)jObject.GetValue("from")).GetValue("x") * 100, (double)((JObject)jObject.GetValue("from")).GetValue("y") * 100),
                    new Point2D((double)((JObject)jObject.GetValue("to")).GetValue("x") * 100, (double)((JObject)jObject.GetValue("to")).GetValue("y") * 100),
                    (float)jObject.GetValue("width") * 100,
                    (float)jObject.GetValue("height") * 100,
                    Color.FromArgb(Convert.ToInt32((string)jObject.GetValue("color"), 16)));
                if (mazeWall.Color.A == 0)
                    mazeWall.Color = Color.LightGray;
                mazeWall.ID = (string)jObject.GetValue("id");
                mazeWalls.Add(mazeWall);
                mazeWallsById.Add((string)jObject.GetValue("id"), mazeWall);
            }
            if (o.GetValue("gates") != null)
            {
                foreach (JObject jObject in o.GetValue("gates").Children())
                {
                    MazeWall mazeWall = new MazeWall(
                        new Point2D((double)((JObject)jObject.GetValue("from")).GetValue("x") * 100, (double)((JObject)jObject.GetValue("from")).GetValue("y") * 100),
                        new Point2D((double)((JObject)jObject.GetValue("to")).GetValue("x") * 100, (double)((JObject)jObject.GetValue("to")).GetValue("y") * 100),
                        0, 0, Color.Black);
                    mazeWall.MazeWallType = MazeWallType.gate;
                    string kind = (string)jObject.GetValue("kind");
                    mazeWall.MazeDoorType = (kind == "door" ? MazeGateType.door : (kind == "passage" ? MazeGateType.passage : MazeGateType.doorOneWayFromTo));      //doorOneWayFromTo will be changed later
                    mazeWall.blocked = (double)jObject.GetValue("blocked");
                    mazeWall.ID = (string)jObject.GetValue("id");
                    mazeWalls.Add(mazeWall);
                    mazeWallsById.Add((string)jObject.GetValue("id"), mazeWall);
                }
            }
            if (o.GetValue("robots") != null)
            {
                JToken tmp;
                Point2D? target;

                foreach (JObject jObject in o.GetValue("robots").Children())
                {
                    if (jObject.TryGetValue("target", out tmp))
                        target = new Point2D((double)((JObject)jObject.GetValue("target")).GetValue("x"), (double)((JObject)jObject.GetValue("target")).GetValue("y"));
                    else
                        target = null;

                    MazeRobot mazeRobot = new MazeRobot(
                        (string)jObject.GetValue("type"),
                        (string)jObject.GetValue("id"),
                        new Point2D((double)((JObject)jObject.GetValue("location")).GetValue("x") * 100, (double)((JObject)jObject.GetValue("location")).GetValue("y") * 100),
                        (float)((JObject)jObject.GetValue("location")).GetValue("z") * 100,
                        //new Point2D((double)((JObject)jObject.GetValue("target")).GetValue("x"),(double)((JObject)jObject.GetValue("target")).GetValue("y"))
                       target

                        );
                    mazeRobot.ID = (string)jObject.GetValue("id");
                    mazeRobots.Add(mazeRobot);
                }
            }
            if (o.GetValue("victims") != null)
            {
                foreach (JObject jObject in o.GetValue("victims").Children())
                {
                    MazeVictim mazeVictim = new MazeVictim(
                        new Point2D((double)((JObject)jObject.GetValue("position")).GetValue("x") * 100, (double)((JObject)jObject.GetValue("position")).GetValue("y") * 100));
                    mazeVictim.ID = (string)jObject.GetValue("id");
                    mazeVictims.Add(mazeVictim);
                }
            }

            Hashtable wallsBySpaceId = new Hashtable();
            if (o.GetValue("space-walls") != null)
            {
                foreach (JObject jObject in o.GetValue("space-walls").Children())
                {
                    string spaceId = (string)jObject.GetValue("spaceId");
                    string wallId = (string)jObject.GetValue("wallId");
                    if (wallsBySpaceId.ContainsKey(spaceId))
                    {
                        ((ArrayList)wallsBySpaceId[spaceId]).Add(mazeWallsById[wallId]);
                    }
                    else
                    {
                        ArrayList newArrayList = new ArrayList();
                        newArrayList.Add(mazeWallsById[wallId]);
                        wallsBySpaceId[spaceId] = newArrayList;
                    }
                }
            }
            if (o.GetValue("space-gates") != null)
            {
                foreach (JObject jObject in o.GetValue("space-gates").Children())
                {
                    string spaceId = (string)jObject.GetValue("spaceId");
                    string wallId = (string)jObject.GetValue("gateId");
                    if (wallsBySpaceId.ContainsKey(spaceId))
                    {
                        ((ArrayList)wallsBySpaceId[spaceId]).Add(mazeWallsById[wallId]);
                    }
                    else
                    {
                        ArrayList newArrayList = new ArrayList();
                        newArrayList.Add(mazeWallsById[wallId]);
                        wallsBySpaceId[spaceId] = newArrayList;
                    }
                }
            }

            if (o.GetValue("spaces") != null)
            {
                foreach (JObject jObject in o.GetValue("spaces").Children())
                {
                    MazeSpace newRoom = new MazeSpace((ArrayList)wallsBySpaceId[(string)jObject.GetValue("id")]);
                    newRoom.ID = (string)jObject.GetValue("id");
                    newRoom.MazeRoomType = (MazeSpaceType)System.Enum.Parse(typeof(MazeSpaceType), (string)jObject.GetValue("kind"));
                    newRoom.Function = (string)jObject.GetValue("function");
                    newRoom.Name = (string)jObject.GetValue("name");
                    newRoom.ExpectedPersonCount = (int)jObject.GetValue("expectedPersonCount");

                    if (jObject.TryGetValue("searched", out tempJObject))
                        newRoom.Searched = (int)jObject.GetValue("searched");

                    mazeSpaces.Add(newRoom);
                    mazeSpacesById[newRoom.ID] = newRoom;

                    foreach (MazeWall roomWall in newRoom.Walls)
                    {
                        if (roomWall.RoomFrom == null)
                            roomWall.RoomFrom = newRoom;
                        else
                            roomWall.RoomTo = newRoom;
                    }
                }
            }

            ///////////////////////////  graph

            Hashtable spacesByNodeId = new Hashtable();
            if (o.GetValue("space-nodes") != null)
            {
                foreach (JObject jObject in o.GetValue("space-nodes").Children())
                {
                    spacesByNodeId[(string)jObject.GetValue("nodeId")] = mazeSpacesById[(string)jObject.GetValue("spaceId")];
                }
            }
            Hashtable gatesByNodeId = new Hashtable();
            if (o.GetValue("gate-nodes") != null)
            {
                foreach (JObject jObject in o.GetValue("gate-nodes").Children())
                {
                    gatesByNodeId[(string)jObject.GetValue("nodeId")] = mazeWallsById[(string)jObject.GetValue("gateId")];
                }
            }

            Hashtable nodesById = new Hashtable();
            if (o.GetValue("nodes") != null)
            {
                foreach (JObject jObject in o.GetValue("nodes").Children())
                {
                    MazeNode node = new MazeNode(new Point2D((double)((JObject)jObject.GetValue("position")).GetValue("x") * 100, (double)((JObject)jObject.GetValue("position")).GetValue("y") * 100),
                        (MazeSpace)spacesByNodeId[(string)jObject.GetValue("id")],
                        gatesByNodeId[(string)jObject.GetValue("id")] as MazeWall);
                    node.ID = (string)jObject.GetValue("id");
                    nodesById[node.ID] = node;
                    mazeGraph.AddNode(node);
                }
            }

            if (o.GetValue("node-nodes") != null)
            {
                foreach (JObject jObject in o.GetValue("node-nodes").Children())
                {
                    MazeNode fromNode = (MazeNode)nodesById[(string)jObject.GetValue("nodeFromId")];
                    MazeNode toNode = (MazeNode)nodesById[(string)jObject.GetValue("nodeToId")];

                    if (fromNode.Door != null && (fromNode.Door.MazeDoorType == MazeGateType.doorOneWayFromTo || fromNode.Door.MazeDoorType == MazeGateType.doorOneWayToFrom))
                    {
                        if (fromNode.Room == fromNode.Door.RoomFrom)
                            fromNode.Door.MazeDoorType = MazeGateType.doorOneWayFromTo;
                        else
                            fromNode.Door.MazeDoorType = MazeGateType.doorOneWayToFrom;
                    }
                    mazeGraph.AddArc(fromNode, toNode);

                    mazeNodeNodes.Add(new MazeNodeNodes(jObject.GetValue("nodeFromId").ToString(), jObject.GetValue("nodeToId").ToString(), double.Parse(jObject.GetValue("cost").ToString()), double.Parse(jObject.GetValue("blocked").ToString())));
                }
            }

            if (o.GetValue("space-nodes") != null)
            {
                foreach (JObject jObject in o.GetValue("space-nodes").Children())
                {
                    mazeSpaceNode.Add(new MazeSpaceNodes(jObject.GetValue("type").ToString(),
                                                         jObject.GetValue("spaceId").ToString(),
                                                         jObject.GetValue("nodeId").ToString()));
                }
            }

            if (o.GetValue("space-robots") != null)
            {
                foreach (JObject jObject in o.GetValue("space-robots").Children())
                {
                    mazeSpaceRobots.Add(new MazeSpaceRobots(jObject.GetValue("type").ToString(),
                                                         jObject.GetValue("spaceId").ToString(),
                                                         jObject.GetValue("robotId").ToString()));
                }
            }

            reader.Close();
        }
        protected void RemoveRoom(MazeSpace room)
        {
            mazeRooms.Remove(room);

            ArrayList nodesToRemove = new ArrayList();
            foreach (MazeNode node in mazeGraph.MazeGraphNodes)
                if (node.Room == room)
                    nodesToRemove.Add(node);
            foreach (MazeNode node in nodesToRemove)
                mazeGraph.RemoveNode(node);
        }
        /// <summary>
        /// 
        /// Common walls required 
        /// Common walls removed with nodes 
        /// 
        /// New Room from remaining walls 
        /// 
        /// All internal arcs removed 
        /// Central node recreated 
        /// Arcs recreated 
        /// 
        /// New Room added, old removed 
        /// 
        /// Trees recreated 
        /// New Room selected
        /// 
        /// </summary>
        /// <param name="firstRoom"></param>
        /// <param name="secondRoom"></param>
        private void TryJoinRooms(MazeSpace firstRoom, MazeSpace secondRoom)
        {
            ArrayList commonWalls = new ArrayList();
            foreach (MazeWall wall in firstRoom.Walls)
                if (secondRoom.Walls.Contains(wall))
                    commonWalls.Add(wall);

            if (commonWalls.Count == 0)
            {
                MessageBox.Show("Cannot join rooms -- common walls not found");
                return;
            }

            ArrayList newRoomWalls = new ArrayList();
            foreach (MazeWall wall in firstRoom.Walls)
                if (!commonWalls.Contains(wall))
                    newRoomWalls.Add(wall);
            foreach (MazeWall wall in secondRoom.Walls)
                if (!commonWalls.Contains(wall))
                    newRoomWalls.Add(wall);

            mazeGraph.RemoveNode(firstRoom.CetralNode);
            mazeGraph.RemoveNode(secondRoom.CetralNode);

            ArrayList nodesToRemove = new ArrayList();
            foreach (MazeWall wall in commonWalls)
            {
                //if(wall.MazeWallType == MazeWallType.gate) //wywalamy tylko drzwi pomieedzy pomiesczeniami
                mazeWalls.Remove(wall);

                foreach (MazeNode node in mazeGraph.MazeGraphNodes)
                    if (node.Door == wall)
                        nodesToRemove.Add(node);
                foreach (MazeNode node in nodesToRemove)
                    mazeGraph.RemoveNode(node);
            }

            foreach (MazeWall wall in commonWalls)
                mazeWalls.Remove(wall);

            /* foreach (MazeWall wall in commonWalls) //dodanie scian wspolnych
             {
                 if (wall.MazeWallType == MazeWallType.wall)
                 {
                     mazeWalls.Add(wall);
                     newRoomWalls.Add(wall);
                 }
             }*/

            MazeSpace newRoom = new MazeSpace(newRoomWalls);
            newRoom.CetralNode = new MazeNode(newRoom.CenterPoint, newRoom, null);
            mazeGraph.AddNode(newRoom.CetralNode);

            foreach (MazeWall wall in newRoomWalls)
            {
                foreach (MazeNode node in mazeGraph.MazeGraphNodes)
                    if (node.Door == wall && (node.Room == firstRoom || node.Room == secondRoom))
                    {
                        node.Room = newRoom;
                        mazeGraph.AddArc(node, newRoom.CetralNode);
                        mazeGraph.AddArc(newRoom.CetralNode, node);
                    }

            }

            mazeRooms.Remove(firstRoom);
            mazeRooms.Remove(secondRoom);
            mazeRooms.Add(newRoom);

            RefreshMazeWallsTreeView();
            recreateGraphTreeView();
            recreateRoomsTreeView();
        }
        private void roomsTreeView_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
        {
            if (roomsTreeView.SelectedNode == null)
                return;

            if (roomsTreeView.SelectedNode.Tag as MazeSpace != null)
            {
                typeSelectComboBox.Items.Clear();
                foreach (MazeSpaceType roomType in Enum.GetValues(typeof(MazeSpaceType)))
                    typeSelectComboBox.Items.Add(roomType);
                typeSelectComboBox.SelectedItem = (roomsTreeView.SelectedNode.Tag as MazeSpace).MazeRoomType;
                doorPropertiesPanel.Visible = false;
                roomPropertiesPanel.Visible = true;
                roomLengthLabel.Text = "space length: " + (roomsTreeView.SelectedNode.Tag as MazeSpace).Diameter.ToString("f2");
                roomAreaLabel.Text = "space area:    " + (roomsTreeView.SelectedNode.Tag as MazeSpace).Area.ToString("f2");
                roomFunctionTextBox.Text = (roomsTreeView.SelectedNode.Tag as MazeSpace).Function;
                spaceNameTextBox.Text = (roomsTreeView.SelectedNode.Tag as MazeSpace).Name;
                roomExpPersonCountNumericUpDown.Value = Math.Min((roomsTreeView.SelectedNode.Tag as MazeSpace).ExpectedPersonCount, roomExpPersonCountNumericUpDown.Maximum);

                if (joinWithRadioButton.Checked)
                {
                    if (previousSelectedRoom != null)
                        TryJoinRooms(previousSelectedRoom, roomsTreeView.SelectedNode.Tag as MazeSpace);

                    joinWithRadioButton.Checked = false;
                }
                if (roomsTreeView.SelectedNode != null)
                    previousSelectedRoom = roomsTreeView.SelectedNode.Tag as MazeSpace;

            }
            else if (roomsTreeView.SelectedNode.Tag as MazeWall != null && (roomsTreeView.SelectedNode.Tag as MazeWall).MazeWallType == MazeWallType.gate)
            {
                typeSelectComboBox.Items.Clear();
                foreach (MazeGateType doorType in Enum.GetValues(typeof(MazeGateType)))
                    typeSelectComboBox.Items.Add(doorType);
                typeSelectComboBox.SelectedItem = (roomsTreeView.SelectedNode.Tag as MazeWall).MazeDoorType;

                doorPropertiesPanel.Visible = true;
                gateBlockedNumericUpDown.Value = (decimal)(roomsTreeView.SelectedNode.Tag as MazeWall).blocked;
                roomPropertiesPanel.Visible = false;

            }
            mazePanel_Paint(this, null);
        }
        private void recreateRoomsButton_Click(object sender, EventArgs e)
        {
            if (mazeGraph != null && MessageBox.Show("This operation will remove the rooms and the graph. It cannot be undone.\n Are you sure?", "", MessageBoxButtons.OKCancel) != DialogResult.OK)
                return;
            mazeGraph = new MazeGraph();
            mazeRooms = new ArrayList();

            roomsTreeView.Nodes.Clear();

            RoomsGraphBuilder roomsGraphBuilder = new RoomsGraphBuilder();
            if (!ConvexOnlyCheckBox.Checked)
            {
                roomsGraphBuilder.GenerateConvexRoomsOnly = false;
                roomsGraphBuilder.SplitRoomsIntoConvex = false;
            }
            foreach (MazeWall wall in mazeWalls)
            {
                if (wall.MazeWallType == MazeWallType.wall)
                    roomsGraphBuilder.AddWall(new Point2D(wall.points[0].X, wall.points[0].Y), new Point2D(wall.points[1].X, wall.points[1].Y));
                else
                    roomsGraphBuilder.AddDoor(new Point2D(wall.points[0].X, wall.points[0].Y), new Point2D(wall.points[1].X, wall.points[1].Y));
            }
            roomsGraphBuilder.BuildRegion();

            Hashtable mazeNodeByRoomasGraphNodes = new Hashtable();
            Hashtable mazeWallsByRoomasGraphWalls = new Hashtable();

            ArrayList oldMazeWalls = mazeWalls;
            mazeWalls = new ArrayList();
            foreach (Room graphBuilderRoom in roomsGraphBuilder.Rooms)
            {
                ArrayList roomWalls = new ArrayList();
                foreach (Wall graphBuilderWall in graphBuilderRoom.Walls)
                {
                    bool oldWallFound = false;
                    foreach (MazeWall mazeWall in oldMazeWalls)     //find old
                    {
                        if (mazeWall.Segment.ContainsSegment(graphBuilderWall.WallSegment))
                        {
                            oldWallFound = true;
                            MazeWall roomWall = new MazeWall(graphBuilderWall.From, graphBuilderWall.To, mazeWall.Width, mazeWall.Height, mazeWall.Color);
                            roomWall.MazeWallType = (graphBuilderWall.Type == Wall.WallType.Solid ? MazeWallType.wall : MazeWallType.gate);
                            int indexOf = mazeWalls.IndexOf(roomWall);
                            if (indexOf >= 0)
                            {
                                roomWall = (MazeWall)mazeWalls[indexOf];
                            }
                            else
                            {
                                mazeWalls.Add(roomWall);
                                mazeWallsByRoomasGraphWalls[graphBuilderWall] = roomWall;
                            }
                            roomWalls.Add(roomWall);
                            break;
                        }
                    }
                    if (!oldWallFound)
                    {
                        MazeWall roomWall = new MazeWall(graphBuilderWall.From, graphBuilderWall.To, 0, 0, Color.Black);
                        int indexOf = mazeWalls.IndexOf(roomWall);
                        if (indexOf >= 0)
                        {
                            roomWall = (MazeWall)mazeWalls[indexOf];
                        }
                        else
                        {
                            roomWall.MazeWallType = MazeWallType.gate;
                            mazeWalls.Add(roomWall);
                            mazeWallsByRoomasGraphWalls[graphBuilderWall] = roomWall;
                        }
                        roomWalls.Add(roomWall);
                    }
                }

                /*              ///reorder walls
                              ArrayList orderedRoomWalls = new ArrayList();
                              orderedRoomWalls.Add(roomWalls[0]);
                              roomWalls.RemoveAt(0);
                              Point2D nextPoint = (roomWalls[0] as Wall).To;
                              while (roomWalls.Count > 0)
                              {
                                  foreach (Wall wall in roomWalls)
                                      if (wall.From.GetDistance(nextPoint) < 0.01)
                                      {
                                          nextPoint = wall.From;
                                          roomWalls.Remove(wall);
                                          orderedRoomWalls.Add(wall);
                                          break;
                                      }
                                      else if (wall.To.GetDistance(nextPoint) < 0.01)
                                      {
                                          nextPoint = wall.To;
                                          roomWalls.Remove(wall);
                                          orderedRoomWalls.Add(wall);
                                          break;
                                      }
                              }
              */
                MazeSpace room = new MazeSpace(roomWalls);
                mazeRooms.Add(room);
                foreach (MazeWall roomWall in roomWalls)
                {
                    if (roomWall.RoomFrom == null)
                        roomWall.RoomFrom = room;
                    else
                        roomWall.RoomTo = room;
                }

                //////////////////////////////////////   nodes

                foreach (RoomsGraph.Node borderNode in graphBuilderRoom.BorderNodes)        //push door-nodes into rooms
                {
                    Vector2D v = new Vector2D(borderNode.DoorWall.From, borderNode.DoorWall.To);
                    v.MakePerpendicular();
                    v.Length = (double)wallWidthNumericUpDown.Value * 100;
                    if (Math.Abs(v.AngleBetween(new Vector2D(borderNode.DoorWall.Center, borderNode.Location))) > Math.PI / 2)
                        v.Inverse();
                    borderNode.Position.X += v.x;
                    borderNode.Position.Y += v.y;
                }

                room.CetralNode = new MazeNode(graphBuilderRoom.CentralNode.Location, room, null);
                mazeNodeByRoomasGraphNodes[graphBuilderRoom.CentralNode] = room.CetralNode;
                mazeGraph.AddNode(room.CetralNode);
                foreach (RoomsGraph.Node n in graphBuilderRoom.BorderNodes)
                {
                    MazeNode mazeGraphNode = new MazeNode(n.Location, room, (MazeWall)mazeWallsByRoomasGraphWalls[n.DoorWall]);
                    mazeNodeByRoomasGraphNodes[n] = mazeGraphNode;
                    room.BorderNodes.Add(mazeGraphNode);
                    mazeGraph.AddNode(mazeGraphNode);
                }
            }

            foreach (RoomsGraph.Arc arc in roomsGraphBuilder.Graph.Arcs)
            {
                if (mazeNodeByRoomasGraphNodes[arc.StartNode] != null && mazeNodeByRoomasGraphNodes[arc.EndNode] != null)
                    mazeGraph.AddArc((MazeNode)mazeNodeByRoomasGraphNodes[arc.StartNode], (MazeNode)mazeNodeByRoomasGraphNodes[arc.EndNode]);
            }

            recreateRoomsTreeView();
            recreateGraphTreeView();
            RefreshMazeWallsTreeView();

            mazePanel_Paint(this, null);
        }
        private void DrawRoom(MazeSpace room, bool fill)
        {
            PointF[] points = new PointF[room.Walls.Count];
            for (int i = 0; i < room.Points.Length; i++)
                points[i] = room.Points[i];

            mazeBitmapGraphics.DrawPolygon(roomPen, points);

            foreach (MazeWall door in room.Walls)
            {
                if (door.MazeWallType == MazeWallType.gate)
                {
                    mazeBitmapGraphics.DrawLine(doorPen, door.points[0], door.points[1]);
                }
            }

            if (fill)
            {
                mazeBitmapGraphics.FillPolygon(roomPen.Brush, points, System.Drawing.Drawing2D.FillMode.Winding);
            }
        }