private bool TryToMergeWire(float x, float y, Pin pin)
        {
            float scaledX = (x - translate.X) / zoom;
            float scaledY = (y - translate.Y) / zoom;

            // find wire that contains touch point
            Wire wireToMerge  = null;
            Pin  startToMerge = null;
            Pin  endToMerge   = null;

            // try to merge wire Pin to current element Pin
            foreach (var pair in Elements.Where(_ => _.Value is Wire))
            {
                var  wire        = pair.Value as Wire;
                bool startBounds = wire.StartBounds.Contains(scaledX, scaledY) == true;
                bool endBounds   = wire.EndBounds.Contains(scaledX, scaledY) == true;
                bool wireBounds  = wire.WireBounds.Contains(scaledX, scaledY) == true;

                // check for wire start pin
                // exlude if wire start is same as pin to merge
                if (startBounds == true && wire.Start != pin)
                {
                    wireToMerge  = wire;
                    startToMerge = wire.Start;
                    break;
                }

                // check for wire end pin
                // exlude if wire end is same as pin to merge
                if (endBounds == true && wire.End != pin)
                {
                    wireToMerge = wire;
                    endToMerge  = wire.End;
                    break;
                }
            }

            // merge wire start
            if (wireToMerge != null && startToMerge != null && startToMerge.Parent == null)
            {
                MergeWireStart(wireToMerge, startToMerge, pin);

                // if pin is wire end than wire is removed
                if (pin == wireToMerge.End)
                {
                    Element value;
                    Elements.TryRemove(wireToMerge.Id, out value);

                    wireToMerge.Start.Wires.Remove(wireToMerge);
                    wireToMerge.End.Wires.Remove(wireToMerge);

                    //Console.WriteLine ("TryToMergeWire: pin==wireToMerge.End, Pin.Id {0} Remove wireToMerge.Id", pin.Id, wireToMerge.Id);
                }

                // check for other end Wires connections to be merged
                UpdateMergedPinWires(pin, wireToMerge, startToMerge);

                // if merged start does not have any connected wires than need to be removed
                if (startToMerge.Wires.Count == 0)
                {
                    Element value;
                    Elements.TryRemove(startToMerge.Id, out value);

                    //Console.WriteLine ("TryToMergeWire: startToMerge.Wires.Count==0, Pin.Id {0} Remove startToMerge.Id", pin.Id, startToMerge.Id);
                }

                // if pin does not have any connected wires than need to be removed
                if (pin.Wires.Count == 0)
                {
                    Element value;
                    Elements.TryRemove(pin.Id, out value);

                    //Console.WriteLine ("TryToMergeWire: pin.Wires.Count==0, Pin.Id {0} Remove pin.Id", pin.Id);
                }
                // otherwise update all wires connected to pin
                else
                {
                    UpdateWires(pin.Wires, 0f, 0f);
                }

                ResetStartAndEndPin();

                return(true);
            }

            // merge wire end
            if (wireToMerge != null && endToMerge != null && endToMerge.Parent == null)
            {
                MergeWireEnd(wireToMerge, endToMerge, pin);

                // if pin is wire start than wire is removed
                if (pin == wireToMerge.Start)
                {
                    Element value;
                    Elements.TryRemove(wireToMerge.Id, out value);

                    wireToMerge.Start.Wires.Remove(wireToMerge);
                    wireToMerge.End.Wires.Remove(wireToMerge);

                    //Console.WriteLine ("TryToMergeWire: pin==wireToMerge.Start, Pin.Id {0} Remove wireToMerge.Id", pin.Id, wireToMerge.Id);
                }

                // check for other end Wires connections to be merged
                UpdateMergedPinWires(pin, wireToMerge, endToMerge);

                // if merged end does not have any connected wires than need to be removed
                if (endToMerge.Wires.Count == 0)
                {
                    Element value;
                    Elements.TryRemove(endToMerge.Id, out value);

                    //Console.WriteLine ("TryToMergeWire: endToMerge.Wires.Count==0, Pin.Id {0} Remove endToMerge.Id", pin.Id, endToMerge.Id);
                }

                // if pin does not have any connected wires than need to be removed
                if (pin.Wires.Count == 0)
                {
                    Element value;
                    Elements.TryRemove(pin.Id, out value);

                    //Console.WriteLine ("TryToMergeWire: pin.Wires.Count==0, Pin.Id {0} Remove pin.Id", pin.Id);
                }
                // otherwise update all wires connected to pin
                else
                {
                    UpdateWires(pin.Wires, 0f, 0f);
                }

                ResetStartAndEndPin();

                return(true);
            }

            return(false);
        }
        public static void Deserialize(string model, ConcurrentDictionary <int, Element> elements)
        {
            if (string.IsNullOrEmpty(model))
            {
                return;
            }

            string type  = null;
            var    lines = model.Split(ModelLineSeparators, StringSplitOptions.RemoveEmptyEntries);

            foreach (var element in lines)
            {
                var args = element.Split(ModelArgSeparators, StringSplitOptions.RemoveEmptyEntries);

                int length = args.Length;
                if (length < 2)
                {
                    continue;
                }

                type = args[0];

                if (string.Compare(type, "Pin", StringComparison.InvariantCultureIgnoreCase) == 0 && length == 4)
                {
                    int   id = int.Parse(args[1]);
                    float x  = float.Parse(args[2]);
                    float y  = float.Parse(args[3]);

                    var pin = new Pin(id, null, x, y, 4f, 3f);
                    elements.TryAdd(id, pin);
                }
                else if (string.Compare(type, "Wire", StringComparison.InvariantCultureIgnoreCase) == 0 && length == 6)
                {
                    int id            = int.Parse(args[1]);
                    int startParentId = int.Parse(args[2]);
                    int startId       = int.Parse(args[3]);
                    int endParentId   = int.Parse(args[4]);
                    int endtId        = int.Parse(args[5]);

                    var wire = new Wire(id, startParentId, startId, endParentId, endtId);
                    elements.TryAdd(id, wire);
                }
                else if (string.Compare(type, "AndGate", StringComparison.InvariantCultureIgnoreCase) == 0 && length == 4)
                {
                    int   id = int.Parse(args[1]);
                    float x  = float.Parse(args[2]);
                    float y  = float.Parse(args[3]);

                    var andGate = new AndGate(id, x, y);
                    elements.TryAdd(id, andGate);
                }
                else if (string.Compare(type, "OrGate", StringComparison.InvariantCultureIgnoreCase) == 0 && length == 4)
                {
                    int   id = int.Parse(args[1]);
                    float x  = float.Parse(args[2]);
                    float y  = float.Parse(args[3]);

                    var orGate = new OrGate(id, x, y, 1);
                    elements.TryAdd(id, orGate);
                }
            }

            UpdateWireConnections(elements);
        }
        private bool TryToDetachWire(float x, float y)
        {
            float scaledX = (x - translate.X) / zoom;
            float scaledY = (y - translate.Y) / zoom;

            // find wire that contains touch point
            Wire wireToDetach  = null;
            Pin  startToDetach = null;
            Pin  endToDetach   = null;

            // try to detach wire Pin from current element
            foreach (var pair in Elements.Where(_ => _.Value is Wire))
            {
                var  wire        = pair.Value as Wire;
                bool startBounds = wire.StartBounds.Contains(scaledX, scaledY) == true;
                bool endBounds   = wire.EndBounds.Contains(scaledX, scaledY) == true;
                bool wireBounds  = wire.WireBounds.Contains(scaledX, scaledY) == true;

                // check for wire start pin
                if (startBounds == true)
                {
                    wireToDetach  = wire;
                    startToDetach = wire.Start;
                    break;
                }

                // check for wire end pin
                if (endBounds == true)
                {
                    wireToDetach = wire;
                    endToDetach  = wire.End;
                    break;
                }
            }

            // detach wire start
            if (wireToDetach != null && startToDetach != null && startToDetach.Parent != null)
            {
                // create standalone pin
                var pin = InsertPin(scaledX, scaledY, false);

                // set detached wire start to standalone pin
                SwapWireStart(wireToDetach, startToDetach, pin);

                // reset start pin
                startToDetach.IsSelected = false;

                // set standalone pin as current element
                currentElement          = pin;
                currentElement.ShowPins = true;

                UpdateWires(pin.Wires, 0f, 0f);

                ResetStartAndEndPin();

                return(true);
            }

            // detach wire end
            if (wireToDetach != null && endToDetach != null && endToDetach.Parent != null)
            {
                // create standalone pin
                var pin = InsertPin(scaledX, scaledY, false);

                // set detached wire end to standalone pin
                SwapWireEnd(wireToDetach, endToDetach, pin);

                // reset start pin
                endToDetach.IsSelected = false;

                // set standalone pin as current element
                currentElement          = pin;
                currentElement.ShowPins = true;

                UpdateWires(pin.Wires, 0f, 0f);

                ResetStartAndEndPin();

                return(true);
            }

            return(false);
        }