/// <summary>
 /// Използва се в методът ChangeBorderWidth за промяна на ширината на контура, ако селектираният елемент е част от група.
 /// </summary>
 /// <param name="group"></param>
 /// <param name="width"></param>
 private void ChangeCascadeBorderWidth(Shape group, int width)
 {
     foreach (Shape item in ((Grouping)group).GroupedElements)
     {
         if (item.isGroup == true)
         {
             ChangeCascadeBorderWidth(item, width);
         }
         else
         {
             item.BorderWidth = width;
         }
     }
 }
 /// <summary>
 /// Използва се в методът ChangeFillColor за промяна на цвета на запълване на селектиран елемент, ако той е част от група от елементи.
 /// </summary>
 /// <param name="group"></param>
 /// <param name="color"></param>
 private void ChangeCascadeFillColor(Shape group, Color color)
 {
     foreach (Shape item in ((Grouping)group).GroupedElements)
     {
         if (item.isGroup == true)
         {
             ChangeCascadeFillColor(item, color);
         }
         else
         {
             item.FillColor = color;
         }
     }
 }
 /*
  * рекурсивното транслиране на всички елементи на подадена група
  */
 private void RecursiveScaleTranslate(int type, RectangleF initialBounds, RectangleF curBounds, Shape item)
 {
     if (item.isGroup)
     {
         Grouping groupe = (Grouping)item;
         foreach (Shape element in groupe.GroupedElements)
         {
             RecursiveScaleTranslate(type,initialBounds,curBounds,element);
         }
     }
     else
     {
         this.SelectedItem.TMatrix.TransformationMatrix = item.TMatrix.TransformationMatrix;
         base.TranslateScaledItem(type, initialBounds, curBounds, item);
     }
 }
 /*
 *Рекурсивен метод за транслиране на всички елемнти на група един по един
  * **/
 private void RecursiveTranslate(Shape element,PointF point)
 {
     if (element.isGroup)
     {
         Grouping groupe = (Grouping)element;
         foreach (Shape item in groupe.GroupedElements)
         {
             RecursiveTranslate(item,point);
         }
     }
     else
     {
         this.SelectedItem.TMatrix.TransformationMatrix = element.TMatrix.TransformationMatrix;
         base.TranslateElementTo(point);
         element.TMatrix.TransformationMatrix = this.SelectedItem.TMatrix.TransformationMatrix;
     }
 }
 /*
 * Рекурсивен метод, който натрупва ротацията върху матриците на трансформация
 * на всички поделементи на групата
 * използва центъра на групата (около него се въртят сички елементи)
 */
 private void RecursiveRotate(Shape element, PointF mLocation,PointF center)
 {
     if (element.isGroup)
     {
         Grouping groupe = (Grouping)element;
         foreach (Shape item in groupe.GroupedElements)
         {
             RecursiveRotate(item, mLocation,center);
         }
     }
     else
     {   // същинската ротация на елемент
         // приравнявам матрицата на групата с тази на елемента защото
         // методът Rotate работи с матрицата на групата
         // и после запазвам промените в матрицата на елемента
         this.SelectedItem.TMatrix.TransformationMatrix = element.TMatrix.TransformationMatrix;
         base.Rotate(mLocation,center);
         element.TMatrix.TransformationMatrix = this.SelectedItem.TMatrix.TransformationMatrix;
     }
 }
 /*
  * рекурсивното скалиране на всички елементи на подадена група
  */
 private void RecursiveScale(PointF point, int type, RectangleF initialBounds, Shape item, PointF iniLocation)
 {
     if (item.isGroup)
     {
         Grouping groupe = (Grouping)item;
         foreach (Shape item2 in groupe.GroupedElements)
         {
             RecursiveScale(point,type, initialBounds,item2,iniLocation);
         }
     }
     else
     {
         this.SelectedItem.TMatrix.TransformationMatrix = item.TMatrix.TransformationMatrix;
         base.ScaleItem(point, type, initialBounds, item, iniLocation);
     }
 }
        public void MouseUp(Point mlocation)
        {
            switch (Event)
            {
                case "DrawPointShape-go":
                    {
                        Point initial = (Point)sDots.ToArray()[0];
                        Point current = mlocation;
                        ((PointShape)itemPointer).SetLocation = new RectangleF(Math.Min(initial.X, current.X) - 1, Math.Min(initial.Y, current.Y) - 1, Math.Max(initial.X, current.X) - Math.Min(initial.X, current.X), Math.Max(initial.Y, current.Y) - Math.Min(initial.Y, current.Y));
                        Event = "";
                        itemPointer = null;
                    }break;

                case "DrawLineShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    } break;

                case "DrawCurveShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    } break;

                case "DrawClosedCurveShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    } break;

                case "DrawSquareShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    }break;

                case "DrawRectangleShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    } break;

                case "DrawEllipseShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    } break;

                case "DrawCircleShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    }break;

                case "DrawEllipseLineIntersectionShape-go":
                    {
                        Event = "";
                        itemPointer = null;
                    } break;

                case "DrawConnectedEllipses-go":
                    {
                        Event = "";
                        itemPointer = null;
                    } break;

                case "DrawPolygonShape-go":
                    {
                        if (sDots.Count == 4)
                        {
                            diProcessor.ObjectsDrawn.Add(new PolygonShape(sDots));
                            Event = "";
                            diProcessor.controlPolygon.Clear();
                        }

                        itemPointer = null;
                    } break;

                case "DrawBezierShape-go":
                    {
                        if (sDots.Count == 4)
                        {
                            itemPointer = new BezierCurveShape();
                            ((BezierCurveShape)itemPointer).pointOne = (Point)sDots.ToArray()[0];
                            ((BezierCurveShape)itemPointer).pointTwo = (Point)sDots.ToArray()[1];
                            ((BezierCurveShape)itemPointer).pointTree = (Point)sDots.ToArray()[2];
                            ((BezierCurveShape)itemPointer).pointFour = (Point)sDots.ToArray()[3];
                            diProcessor.ObjectsDrawn.Add(itemPointer);
                            itemPointer = null;
                            Event = "";
                            diProcessor.controlPolygon.Clear();
                        }

                        itemPointer = null;
                    } break;

                case "DrawTriangleShape-go":
                    {
                        if (sDots.Count == 3)
                        {
                            diProcessor.ObjectsDrawn.Add(new PolygonShape(sDots));
                            Event = "";
                            diProcessor.controlPolygon.Clear();
                        }

                        itemPointer = null;
                    } break;

                default:
                    {
                        if (diProcessor.IsDraging)
                        {
                            diProcessor.IsDraging = false;
                            diProcessor.InitialLocation = mlocation;
                            MainWindow.ActiveForm.Cursor = System.Windows.Forms.Cursors.Default;
                        }
                        else
                        {
                            if (diProcessor.multySelect)
                            {
                                diProcessor.HandleMultySelecting();
                                MainWindow.ActiveForm.Cursor = System.Windows.Forms.Cursors.Default;
                                diProcessor.multySelect = false;

                            }
                        }
                    } break;
            }
        }
 /*
  * Секция Скалиране
  * тук има 2 рекурсивни метода, защото скалирането на групи се свежда до скалиране(което се извършва спрямо
  * центъра на координатната система и след това транслиране, за да противодейства на възникналите промени.
  * Методът предефинира предщественика си с цел подържане на скалиране на групи.
  */
 protected override void Action(PointF point, int type, RectangleF initialBounds, Shape item, PointF iniLocation)
 {
     //ако елемента не е група ползва метода на предшественика си
     if (item.isGroup != true)
     {
         base.Action(point, type, initialBounds, item, iniLocation);
     }
     else
     {
         // ако е група първо скалира всички поелемти на групата
         RecursiveScale(point, type, initialBounds, item, iniLocation);
         // след това един по един ги транслира
         RecursiveScaleTranslate(type, initialBounds, item.ReturnBounds(), item);
     }
 }
        /*транслиране на скалиран елемент*/
        protected virtual void TranslateScaledItem(int type, RectangleF initialBounds, RectangleF curBounds, Shape item)
        {
            //има само 4 различни вида другите са им производни
            float tY=1, tX=1;

            if ( type == 7)
            {
                type = 0;
            }
            if ( type == 2)
            {
                type = 1;
            }
            if ( type == 4 || type == 6)
            {
                type = 3;
            }
            switch (type)
            {
                case 0:
                    {
                            tX = (initialBounds.X + initialBounds.Width) - (curBounds.X + curBounds.Width);
                            tY = (initialBounds.Y + initialBounds.Height) - (curBounds.Y + curBounds.Height);
                    }; break;

                case 1:
                    {
                            tX = initialBounds.X - curBounds.X;
                            tY = (initialBounds.Y + initialBounds.Height) - (curBounds.Y + curBounds.Height);
                    }; break;

                case 3:
                    {
                            tX = (initialBounds.Location.X - curBounds.Location.X);
                            tY = (initialBounds.Location.Y - curBounds.Location.Y);
                    } break;

                case 5:
                    {
                            tX = (initialBounds.X + initialBounds.Width) - (curBounds.X + curBounds.Width);
                            tY = initialBounds.Y - curBounds.Y;
                    }; break;
            }

            item.TMatrix.Translate(tX, tY);
        }
        /// <summary>
        /// При кликване в пространството за рисуване приeма координатите.
        /// </summary>
        /// <param name="mLocation"></param>
        public void MouseDown(Point mLocation)
        {
            switch(Event)
            {
                case "DrawPointShape":
                    {
                        Event = "DrawPointShape-go";
                        itemPointer = new PointShape();
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);
                    }break;

                case "DrawLineShape":
                    {
                        Event = "DrawLineShape-go";
                        itemPointer = new LineShape(new Point(-1, -1), new Point(-1, -1));
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);
                    } break;

                case "DrawSquareShape":
                    {
                        Event = "DrawSquareShape-go";
                        itemPointer = new SquareShape();
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);
                    }break;

                case "DrawRectangleShape":
                    {
                        Event = "DrawRectangleShape-go";
                        itemPointer = new RectangleShape();
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);
                    } break;

                case "DrawEllipseShape":
                    {
                        Event = "DrawEllipseShape-go";
                        itemPointer = new EllipseShape();
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);

                    } break;

                case "DrawEllipseLineIntersectionShape":
                    {
                        Event = "DrawEllipseLineIntersectionShape-go";
                        itemPointer = new EllipseLineIntersectionShape();
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);
                    } break;

                case "DrawConnectedEllipses":
                    {
                        Event = "DrawConnectedEllipses-go";
                        itemPointer = new ConnectedEllipses();
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);
                    } break;

                case "DrawCircleShape":
                    {
                        Event = "DrawCircleShape-go";
                        itemPointer = new CircleShape();
                        diProcessor.ObjectsDrawn.Add(itemPointer);
                        sDots.Clear();
                        sDots.Add(mLocation);
                    }break;

                case "DrawCurveShape":
                    {
                        sDots = new ArrayList();
                        sDots.Add(mLocation);
                        Event = "DrawCurveShape-go";
                        itemPointer = new CurveShape(sDots);
                        diProcessor.ObjectsDrawn.Add(itemPointer);

                    } break;

                case "DrawClosedCurveShape":
                    {
                        sDots = new ArrayList();
                        sDots.Add(mLocation);
                        Event = "DrawClosedCurveShape-go";
                        itemPointer = new ClosedCurveShape(sDots);
                        diProcessor.ObjectsDrawn.Add(itemPointer);

                    } break;

                case "DrawPolygonShape":
                    {
                        Event = "DrawPolygonShape-go";
                        diProcessor.controlPolygon.Add(new LineShape(mLocation, mLocation));
                        sDots.Clear();
                        sDots.Add(mLocation);

                    } break;

                case "DrawBezierShape":
                    {
                        Event = "DrawBezierShape-go";
                        sDots.Clear();
                        sDots.Add(mLocation);
                        diProcessor.controlPolygon.Add(new LineShape(mLocation, mLocation));
                    } break;

                case "DrawTriangleShape":
                    {
                        Event = "DrawTriangleShape-go";
                        sDots.Clear();
                        sDots.Add(mLocation);
                        diProcessor.controlPolygon.Add(new LineShape(mLocation, mLocation));

                    } break;

                case "DrawTriangleShape-go":
                    {
                        sDots.Add(mLocation);
                        diProcessor.controlPolygon.Add(new LineShape(mLocation, mLocation));
                    } break;

                case "DrawPolygonShape-go":
                    {
                       sDots.Add(mLocation);
                       diProcessor.controlPolygon.Add(new LineShape(mLocation, mLocation));
                    } break;

                case "DrawBezierShape-go":
                    {
                        sDots.Add(mLocation);
                        diProcessor.controlPolygon.Add(new LineShape(mLocation, mLocation));
                    } break;

                default:
                    {
                        // проверка дали е кликнато в някоя фигура
                        diProcessor.ContainsPoint(mLocation);
                        //ако е
                        if (diProcessor.SelectedItem != null)
                        {
                            diProcessor.messageToStrip = diProcessor.SelectedItem.Name;
                            //ако е кликнато на бутон от селектора
                            if (diProcessor.SelectedItem.selectionUnit.ContainsPoint(mLocation) > -1)
                            {
                                //задаваме действие оразмеряване
                                this.Event = "Scale";

                                //елемента може да се влачи
                                diProcessor.IsDraging = true;

                                //записваме индекса на операцията в процесора
                                diProcessor.selectionUnitIndex = diProcessor.SelectedItem.selectionUnit.ContainsPoint(mLocation);

                                // определяме типа на курсора на мишката
                                switch (diProcessor.selectionUnitIndex)
                                {
                                    case 0: // горен десен
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeNWSE;
                                        } break;

                                    case 1: // горен ляв
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeNESW;
                                        } break;

                                    case 2: // горе център
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeNS;
                                        }break;

                                    case 3: // десен център
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeWE;
                                        }break;

                                    case 4: // долен десен
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeNWSE;
                                        }break;

                                    case 5: // долен ляв
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeNESW;
                                        }break;

                                    case 6: // горен десен
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeNS;
                                        }break;

                                    case 7: // ляв център
                                        {
                                            MainWindow.ActiveForm.Cursor = Cursors.SizeWE;
                                        }break;

                                    case 8: // тук ѝ задавaме действие ротация
                                        {
                                            MainWindow.ActiveForm.Cursor = RotationCursor;
                                            this.Event = "RotateAt";
                                        }break;
                                }
                            }
                            else
                            {
                                //в случай, че сме кликнали в някой елемент го подготвяме за транслация
                                diProcessor.IsDraging = true;
                                this.Event = "TranslateElementTo";

                                // Променяме и курсора
                                MainWindow.ActiveForm.Cursor = Cursors.SizeAll;
                            }
                        }
                        else
                        {
                            diProcessor.multySelect = true;
                            MainWindow.ActiveForm.Cursor = Cursors.Cross;
                        }

                        // задаваме начална позиция
                        diProcessor.InitialLocation = mLocation;
                        diProcessor.mCurentLocation = mLocation;
                    } break;
            }
        }
        /*склаиране на елемент*/
        protected virtual void ScaleItem(PointF point, int type, RectangleF initialBounds, Shape item, PointF iniLocation)
        {
            // взема границите на фигурата

            Matrix tempMatrix = new Matrix();
            float X, Y;
            X = point.X - iniLocation.X;
            Y = point.Y - iniLocation.Y;
            // спрямо бутона(случая) определяме вида на скалирането
            switch (type)
            {
                case 0:
                    {
                            X = initialBounds.Width / (X + initialBounds.Width);
                            Y = initialBounds.Height / (Y + initialBounds.Height);
                    }; break;

                case 1:
                    {
                            X = (X + initialBounds.Width) / initialBounds.Width;
                            Y = initialBounds.Height / (Y + initialBounds.Height);
                    }; break;
                case 2:
                    {
                            X = 1;
                            Y = initialBounds.Height / (Y + initialBounds.Height);
                    }; break;
                case 3:
                    {
                            X = (initialBounds.Width + X) / (initialBounds.Size.Width);
                            Y = 1;
                    } break;
                case 4:
                    {
                            X = (initialBounds.Width + X) / (initialBounds.Size.Width);
                            Y = (initialBounds.Height + Y) / (initialBounds.Size.Height);
                    } break;
                case 5:
                    {
                            X = initialBounds.Width / (X + initialBounds.Width);
                            Y = (Y + initialBounds.Height) / initialBounds.Height;
                    }; break;
                case 6:
                    {
                            X = 1;
                            Y = (initialBounds.Height + Y) / (initialBounds.Size.Height);
                    } break;

                case 7:
                    {
                            X = initialBounds.Width / (X + initialBounds.Width);
                            Y = 1;
                    }; break;
            }
            item.TMatrix.Scale(X, Y);
            //слага в полето с колко е скалиран обекта по ширина и височина
            message = "Оразмеряване: " + "X: " + X + "%; Y: " + Y + "%;";
            return;
        }
        /*              КАК РАБОТИ СКАЛИРАНЕТО!!!
         *           този коментар е обхваща функционалността на 3 функции
         *              1)MatchType
         *              2)ScaleItem
         *              3)TranslateScaledItem
         *
            * Написаното тук е валидно за всички 7 случая (коментара де не кода)!
         * 1)
            * Първо проверяваме дали (ширината на обекта - разтоянието) е положително число.
            * Правим същото и за височината.
            * Сравнявам с 2 понеже всичките ми координати са float (с цел мащабиране*),
            * ако се вземе по малка стойност има опасност в даден случай да получиме
            * initialBounds.Width/(X - initialBounds.Width),
            * където initialBounds.Width е число >0 а (X - initialBounds.Width) да клони към 0
            * или x/n при n клонящо към 0 - демек неопределеност.
         * 2)
            * След това се изчисляват Х и Y , които всъщност указват изменеието на размера
            * спрямо текущия размер.
            * Правим си матрица и записваме Х и Y,скалираме е и след това е умноваваме по
            * матрицата на трансформация на обекта.
         * 3)
            * Приравняваме получената матрица на матрицата на трансформация на обекта.
            * Накрая изчисляваме координатите, на които да транслираме обекта-
            *  това го правиме за да не се мести фигурата при склаирането.
            *  има 7 случая - по 1 за всяко квадратче от указващия четириъгъллник.
            * **/
        /*
         * По подадения тип на скалиране определя дали е възможно чрез серия от проверки
         * и ако е извиква метода Action, който всъщност извиква методите за скалиране и транслиране.
         * Направено е с толкоз много методи, не за кеф, а понеже при следващия клас, който наследява този
         * и добая скалиране на групи се предифинра само 1 малък метод, а не се пренаписва сичко
         * **/
        protected virtual void MatchType(PointF point, int type, RectangleF initialBounds ,Shape item,PointF iniLocation)
        {
            float X ,Y;
                //изчисляваме разтоянието м/у началната позиция и текущата
                X = point.X - iniLocation.X;
                Y = point.Y - iniLocation.Y;
                bool flag=false;
               // спрямо бутона(случая) определяме вида на скалирането
                switch (type)
                {

                    case 0:
                        {
                            if (((initialBounds.Width - X) > 2) && ((initialBounds.Height - Y) > 2))
                            {
                                flag = true;
                            }
                        }; break;

                    case 1:
                        {
                            if (((initialBounds.Width + X) > 2) && ((initialBounds.Height -Y) > 2))
                            {
                                flag = true;
                            }
                        }; break;
                    case 2:
                        {
                            if ( ((initialBounds.Height - Y) > 2))
                            {
                                flag = true;
                            }
                        }; break;
                    case 3:
                        {

                            if ((initialBounds.Width + X) > 2)
                            {
                                flag = true;
                            }

                        } break;
                    case 4:
                        {

                            if (((initialBounds.Width + X) > 2) && (initialBounds.Height+ Y) > 2)
                            {
                                flag = true;
                            }

                        } break;
                    case 5:
                        {
                            if (((initialBounds.Width - X) > 2) && ((initialBounds.Height + Y) > 2))
                            {
                                flag = true;
                            }
                        }; break;
                    case 6:
                        {
                            if ((initialBounds.Height + Y) > 2)
                            {
                                flag = true;
                            }
                        } break;

                    case 7:
                        {
                            if (((initialBounds.Width - X) > 2))
                            {
                                flag = true;
                            }
                        }; break;
                }
                if (flag == true)
                {
                    this.Action(point, type, initialBounds, item, iniLocation);
                }
            //слага в полето с колко е скалиран обекта по ширина и височина
                message = "Оразмеряване: " + "X: " + X + "%; Y: " + Y + "%;";
                return;
        }
 /*функцията се извиква от MatchType и извиква ScaleItem и TranslateScaledItem*/
 protected virtual void Action(PointF point, int type, RectangleF initialBounds, Shape item, PointF iniLocation)
 {
     this.ScaleItem(point, type, initialBounds, item, iniLocation);
     this.TranslateScaledItem(type, initialBounds, item.ReturnBounds(), item);//tuka 6te imam qdove
 }
 // селектирания елемент -null aко няма такъв
 /* проверява дали дадена точка е във фигурата
   * извиква си метода на фигурата - независи от класа на фигурата
   */
 public void ContainsPoint(Point point)
 {
     // прави всички фигури неселектирани
     ResetDrawnObjects();
     //цикъл за обхождане - в обратен ред понеже последните фигури,които са
     // изчертани са най-отгоре
     for (int i = ObjectsDrawn.Count - 1; i >= 0; i--)
     {
         if (ObjectsDrawn[i].ContainsPoint(point))
         {
             SelectedItem = ObjectsDrawn[i]; // селектирания обект е този с точката
             selectedItem.Selected = true;
             return  ;
         }
     }
     // изчистваме селектирания елемент иначе използва последния селектиран
     selectedItem = null;
     return ;
 }
 /*
  * Иавиква метода самоизчертаване на фигурата
  * **/
 protected virtual void DrawElement(Shape Element, Graphics Grafics)
 {
     Element.DrawYourSelf(Grafics);
 }