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 void HandleOneInputDown(float x, float y)
        {
            float scaledX  = (x - translate.X) / zoom;
            float scaledY  = (y - translate.Y) / zoom;
            bool  haveWire = false;
            bool  havePin  = false;

            // update previous position
            previousX = scaledX;
            previousY = scaledY;

            // set pan start position
            SetPanStart(x, y);

            // check for wires
            // - if no current element selected
            // - if have start pin to split wires
            if (currentElement == null)
            {
                haveWire = HitTestWire(scaledX, scaledY, true);
            }
            else if (currentElement != null && (startPin != null && endPin == null))
            {
                haveWire = HitTestWire(scaledX, scaledY, false);
            }

            // check for current element pins
            if (currentElement != null && currentElement.ShowPins == true &&
                !(currentElement is Pin) &&
                (startPin == null || endPin == null) &&
                haveWire == false)
            {
                havePin = HitTestPin(scaledX, scaledY);
            }

            if (startPin != null && endPin != null &&
                havePin == true && haveWire == false)
            {
                Snapshot();
                InsertWire(startPin, endPin, false);
            }
            else if (havePin == false && haveWire == true)
            {
                // split wire
                if (startPin != null && endPin == null)
                {
                    Snapshot();

                    // deselect current wire
                    SetWireSelection(currentWire, false, null);

                    // split current wire
                    SplitWire(currentWire, scaledX, scaledY, true);
                }
            }
            else if (havePin == false && haveWire == false)
            {
                bool haveElement = HitTestElement(scaledX, scaledY);

                // reset current element and start&end pins
                // if current element is not present and do not have start pin
                if (haveElement == false && !(startPin != null && endPin == null))
                {
                    ResetStartAndEndPin();
                    currentElement = null;
                }
                else if (haveElement == false && startPin != null && endPin == null)
                {
                    Snapshot();

                    // create standalone pin
                    var pin = InsertPin(scaledX, scaledY, false);
                    InsertWire(startPin, pin, false);

                    // reset previous start pin
                    startPin.IsSelected = false;

                    // set new start pin
                    startPin            = pin;
                    startPin.IsSelected = true;
                    currentElement      = pin;
                }
                // reset start and end pins if have new element selected
                // and start and end pin has beed already connected
                else if (haveElement == true && startPin != null && endPin != null)
                {
                    ResetStartAndEndPin();
                }
            }
        }
        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);
        }