#include "Arrow2.h"

#include <QtGui>




QList<QLineF> Arrow2::calculate_FlyingArrows()
{
    QList<QLineF> line;
    QPointF p1,p2,currentP;
    p1=blockPoint1(myEndItem,type2);
    p2=p1;
    if(flyingType == up)
    {
        //p2.setY(p2.y()-1.5*heighRectangle);
        p2.setY(MIN_HEIGHT + 55);
    }
    if(flyingType == back)
    {
        //p2.setX(p2.x()-1.5*heighRectangle);
        p2.setX(MIN_WIDTH + 5);
    }
    if(flyingType == down)
    {
       // p2.setY(p2.y()+1.5*heighRectangle);
        p2.setY(MAX_HEIGHT - 55);
    }
    if(flyingType == front)
    {
       // p2.setX(p2.x()+4.5*heighRectangle);
        p2.setX(MAX_WIDTH - 5);
    }
    line<<QLineF(p2,p1);
    line<<makeArrow(QLineF(p2,p1));
    return line;
}



QList<QLineF> Arrow2::calculate_points()
{
    QList<QLineF> line; //возвращаемое значение
    QPointF p1,p2,currentP;
    //1
    p1=blockPoint1(myStartItem,type2);
    p2=blockPoint2(myStartItem,type2);
    line<<QLineF(p1,p2);
    currentP=p2;
    //3
    if( /*blockPoint2(myStartItem,type2).x() < blockPoint2(myEndItem,back).x() ||*/
            ( blockPoint2(myEndItem,back).x() < blockPoint2(myStartItem,type2).x() &&
              blockPoint2(myStartItem,type2).x() < myEndItem->pos().x()+widthRectangle)
              )
    {
        if(p2 != numLength())
        {
            line<<QLineF(p2,numLength());
            currentP=numLength();
        }
    }
    //4
    //if( currentP.y() != blockPoint2(myEndItem,type2).y() /*&& currentP.x() > blockPoint2(myEndItem,type2).x()*/ )
    //{
        line<<QLineF(currentP, firstY(currentP));
        currentP=firstY(currentP);
    //}
    //5
        p2=blockPoint2(myEndItem,type2);
        if(p2 != currentP)
        {
            line<<QLineF(currentP,firstX(currentP));
            currentP=firstX(currentP);
        }
        //6
        if(p2 != currentP)
        {
            line<<QLineF(currentP,secondX(currentP));
            currentP=secondX(currentP);
        }
        //2
        p1=blockPoint1(myEndItem,type2);
        p2=blockPoint2(myEndItem,type2);
        line<<QLineF(p2,p1);
        arcs<<makeArk(line, R);
        //делаем наконечник стрелки
        line<<makeArrow(QLineF(p2,p1));
        return line;
}



QPointF Arrow2::getStartCoordinates(DiagramItem * Item, int countArrAtStart)
{
    QPointF pStart = Item->pos();
    pStart.setX(pStart.x()+100);
    pStart.setY(pStart.y() + 2*widthPen*countArrAtStart * pow(-1.0,countArrAtStart));
    return pStart;
}

QPointF Arrow2::getEndCoordinates(DiagramItem * Item, enum TypeIn _type)
{
    int count=0;
    count=countOneTypeArrows(_type, Item);
    //сдвиг = порядковому номеру в массиве

    int shiftPixels=getEndArrowIndexInMassive(_type);    //порядковый номер стрелки в блоке

    QPointF pEnd = Item->pos();

    if(type2 == back)
    {
        pEnd.setX(pEnd.x()-100);
        pEnd.setY(pEnd.y() + 2*widthPen*shiftPixels * pow(-1.0,shiftPixels));
    }
    if(type2 == up)
    {
        pEnd.setX(pEnd.x() +2*widthPen*shiftPixels * pow(-1.0,shiftPixels));
        pEnd.setY(pEnd.y()-50);
    }
    if(type2 == down)
    {
        pEnd.setX(pEnd.x() +2*widthPen*shiftPixels * pow(-1.0,shiftPixels));
        pEnd.setY(pEnd.y()+50);
    }
    return pEnd;
}

void Arrow2::updatePosition()
{
    lines.clear();
    arcs.clear();
    if(!isFlyingArrow)
        lines << calculate_points(); //нашли линии
    else
        lines << calculate_FlyingArrows();
    //отрисовали их
    //хитрожопый способ вызвать отрисовку линий)))
    hide();
    show();
}

enum Arrow2::TypeIn Arrow2::claculateTypeIn(QPointF mypEnd, DiagramItem *myEndItem)
{
    enum TypeIn _type=back;
    QPointF p=myEndItem->pos();

    // x:[40;width] y:[heigh-25;heigh]
    if(  myEndItem->pos().y()+heighRectangle/2.0-25.0 <= mypEnd.y() && myEndItem->pos().y()+heighRectangle/2.0 >= mypEnd.y()
      && myEndItem->pos().x()-widthRectangle/2.0+40.0 <= mypEnd.x()  && myEndItem->pos().x()+widthRectangle/2.0 >= mypEnd.x()
         )
        _type=down ;
    // x:[40;width] y:[0;25]
    if( myEndItem->pos().y()-heighRectangle/2.0 <= mypEnd.y()  &&  myEndItem->pos().y()-heighRectangle/2.0+25 >= mypEnd.y()
      &&  myEndItem->pos().x()-widthRectangle/2.0+40 <= mypEnd.x()  && myEndItem->pos().x()+widthRectangle/2.0 >= mypEnd.x()
         )
        _type= up ;
    // x:[0;40] y:[0;heigh]
    if( myEndItem->pos().y()-heighRectangle/2.0 <= mypEnd.y()  && myEndItem->pos().y()+heighRectangle/2.0 >= mypEnd.y()
      &&  myEndItem->pos().x()-widthRectangle/2.0 <=mypEnd.x()  && myEndItem->pos().x()-widthRectangle/2.0+40.0 >= mypEnd.x()
         )
        _type=back;
    return _type;
}

int Arrow2::countOneTypeArrows(enum TypeIn _type, DiagramItem *item)
{
    int count=0;
    for(int i=0; i<item->ArrowsCount(); i++)
    {
        if(item->arrowAt(i)->type2 == _type)
            count++;
    }
    return count;
}

int Arrow2::getEndArrowIndexInMassive(enum TypeIn _type)
{
    int shiftPixels=0;

        for(int i=0; i<myEndItem->ArrowsCount(); i++)
        {
            //для обычных
            if(myEndItem->arrowAt(i)->type2 == _type &&
                    myEndItem->arrowAt(i)->myEndItem->id() == myEndItem->id())
            {
                if( ID == myEndItem->arrowAt(i)->getID() )   goto exit;
                else    shiftPixels++;
            }
        }
    exit:
    return shiftPixels;
}
   /*
QList<QLineF> Arrow2::ifBack(struct ParametrsForArrow paramArrow)
{
    QList<QLineF> line;
 QPointF currentP, p1, p2;

    currentP=paramArrow.pStart;
    currentP.setX( currentP.x() +10 +R +R*paramArrow.shiftPixelsStart );   //длина стрелки, выходящей из прямоугольника
    if( currentP.x() >= paramArrow.pEnd.x()  && currentP.x() -paramArrow.pEnd.x() <= widthRectangle)
        currentP.setX( currentP.x()+
                       ( widthRectangle +10 +R*paramArrow.shiftPixelsEnd  - (currentP.x()- paramArrow.pEnd.x()) )
                       );   //дополнительное удлиннение(чтобы при подъеме/спуске не пересек второй прямоугольник)

        line.append( QLineF(paramArrow.pStart, currentP) );

        //поднимаем  или опускаем после выхода из блока
        p1=currentP;
        //если вход спереди
        if( paramArrow.pStart.x()+15*paramArrow.countOneType_Start    <=    paramArrow.pEnd.x()+15*paramArrow.countOneType_End )
        {
                    //поднимаем  или опускаем после выхода из блока
                    currentP.setY( paramArrow.pEnd.y() );
                    line.append( QLineF(p1, currentP) );
                    //доводим до конца
                    line.append( QLineF(currentP, paramArrow.pEnd) );
        }
        //если вход сзади
        else
        {
                //поднимаем  или опускаем после выхода из блока
                currentP.setY( paramArrow.pEnd.y()+ heighRectangle/2.0 + 80);
                line.append( QLineF(p1, currentP) );

        //назад
                p1=currentP;
        currentP.setX(paramArrow.pEnd.x() - 15*paramArrow.countOneType_End - widthRectangle/2.0 - 10);
                line.append( QLineF(p1, currentP) );
                //вверх/вниз
                p1=currentP;
        currentP.setY(paramArrow.pEnd.y());
                line.append( QLineF(p1, currentP) );
            //довести до входа
                line.append( QLineF(currentP, paramArrow.pEnd) );

    return line;
}
    }*/
/*
struct Arrow2::ParametrsForArrow Arrow2::calculate_paramArrow()
{
    ParametrsForArrow paramArrow;

    paramArrow.currentType=type2; //вычислить куда входит стрелка(верх,зад,низ)
    //количество "однотипных стрелок"
    paramArrow.countOneType_Start = countOneTypeArrows(type2, myStartItem);
    paramArrow.countOneType_End = countOneTypeArrows(type2, myEndItem);

    //порядковый номер стрелки в блоке
    paramArrow.shiftPixelsStart = countStartArrows(myStartItem);
    paramArrow.shiftPixelsEnd = getArrowIndexInMassive(myEndItem, paramArrow.countOneType_End);

    //получить координаты точки-выхода на блоке
    paramArrow.pStart=getStartCoordinates(myStartItem, paramArrow.shiftPixelsStart);
    paramArrow.pEnd=getEndCoordinates(myEndItem, type2);

    return paramArrow;
}
*/

int Arrow2::countStartArrows()
{
    int count=0;
    for(int i=0; i< myStartItem->ArrowsCount(); i++)
    {
        if(myStartItem->arrowAt(i)->myStartItem->id() == myStartItem->id())
            count++;
    }
    return count;
}


//ВОЗВРАЩАЕТ: количество ВХОДЯЩИХ стрелок у myStartItem с типом = "_type"
int Arrow2::countOneTypeArrows_myStartItem(enum TypeIn _type)
{
    int count=0;
    for(int i=0; i< myStartItem->ArrowsCount(); i++)
    {
        if( myStartItem->id() == myStartItem->arrowAt(i)->myEndItem->id() )
        {
            if( _type == myStartItem->arrowAt(i)->type2 )
                count++;
        }
    }
    return count;
}



int Arrow2::indexStartInMass()
{
    int index=0;
    int o=myStartItem->ArrowsCount();
    for(int i=0; i<myStartItem->ArrowsCount(); i++)
    {
        if(myStartItem->arrowAt(i)->myStartItem->id() == myStartItem->id())
        {
            if(myStartItem->arrowAt(i)->getID() == ID)
                goto end;
            else    index++;
        }
    }

    end:
    return index;
}



QPointF Arrow2::blockPoint1(DiagramItem *Item, enum TypeIn _type)
{
    int count=0;
    int tempShift;
    QPointF posItem;
    if( Item->id() == myStartItem->id() )
    {
        int shiftPixels=indexStartInMass();
        //считаем точку на выходе
        posItem = Item->pos();
        posItem.setX(posItem.x()+100);

        tempShift = 2*widthPen*shiftPixels * pow(-1.0,shiftPixels);
        while (abs(tempShift) > heighRectangle / 2 - 5)
        {
            if (tempShift > 0)
            {
                tempShift = tempShift - heighRectangle / 2 + 7;
            }
            if (tempShift < 0)
            {
                tempShift = tempShift + heighRectangle / 2 - 7;
            }
        }
        posItem.setY(posItem.y() + tempShift);
    }
    else
    {
        //количество уже имеющихся стрелок
        for(int i=0; i< Item->ArrowsCount(); i++)
        {
            if( Item->id() == Item->arrowAt(i)->myEndItem->id() )
            {
                if( _type == Item->arrowAt(i)->type2 )
                     count++;
            }
        }
        //почистать точку
        int shiftPixels=getEndArrowIndexInMassive(_type);    //порядковый номер стрелки в блоке

        posItem = Item->pos();

        if(_type == back)
        {
            posItem.setX(posItem.x()-100);

            tempShift = 2*widthPen*shiftPixels * pow(-1.0,shiftPixels);
            while (abs(tempShift) > heighRectangle / 2 - 5)
            {
                if (tempShift > 0)
                {
                    tempShift = tempShift - heighRectangle / 2 + 7;
                }
                if (tempShift < 0)
                {
                    tempShift = tempShift + heighRectangle / 2 - 7;
                }
            }
            posItem.setY(posItem.y() + tempShift);
        }
        if(_type == up)
        {
            tempShift = 2*widthPen*shiftPixels * pow(-1.0,shiftPixels);
            while (abs(tempShift) > widthRectangle / 2 - 5)
            {
                if (tempShift > 0)
                {
                    tempShift = tempShift - widthRectangle / 2 + 9;
                }
                if (tempShift < 0)
                {
                    tempShift = tempShift + widthRectangle / 2 - 9;
                }
            }
            posItem.setX(posItem.x() + tempShift);

            posItem.setY(posItem.y()-50);
        }
        if(_type == down)
        {
            tempShift = 2*widthPen*shiftPixels * pow(-1.0,shiftPixels);
            while (abs(tempShift) > widthRectangle / 2 - 5)
            {
                if (tempShift > 0)
                {
                    tempShift = tempShift - widthRectangle / 2 + 9;
                }
                if (tempShift < 0)
                {
                    tempShift = tempShift + widthRectangle / 2 - 9;
                }
            }
            posItem.setX(posItem.x() + tempShift);

            posItem.setY(posItem.y()+50);
        }
        if(_type == front)
        {
            posItem.setX(posItem.x()+100);
            tempShift = 2*widthPen*shiftPixels * pow(-1.0,shiftPixels);
            while (abs(tempShift) > heighRectangle / 2 - 5)
            {
                if (tempShift > 0)
                {
                    tempShift = tempShift - heighRectangle / 2 + 7;
                }
                if (tempShift < 0)
                {
                    tempShift = tempShift + heighRectangle / 2 - 7;
                }
            }
            posItem.setY(posItem.y() + tempShift);
        }
    }
    return posItem;
}


QPointF Arrow2::blockPoint2(DiagramItem *Item, enum TypeIn _type)
{
    int tempShift;
    QPointF point1=blockPoint1(Item, _type);
    int shiftPixels=getEndArrowIndexInMassive(_type);

    if( Item->id() == myStartItem->id() )
    {
        shiftPixels=indexStartInMass();

        point1.setX(point1.x() +R +2*widthPen*shiftPixels);
    }
    else
    {
        if(_type == back)
        {
            point1.setX(point1.x()  -R -2*widthPen*shiftPixels );
        }
        if(_type == up)
        {
            point1.setY(point1.y()  -R -2*widthPen*shiftPixels );
        }
        if(_type == down)
        {
            point1.setY(point1.y()  +R +2*widthPen*shiftPixels );
        }
    }

    return point1;
}
QPointF Arrow2::numLength()
{
    QPointF pS  =blockPoint2(myStartItem,type2);
    QPointF currentP =pS;
    QPointF pE_back  =blockPoint2(myEndItem,back);
    QPointF pE  =blockPoint2(myEndItem,type2);

    //магия
    DiagramItem *bufStartItem=myStartItem;
    DiagramItem *bufEndItem=myEndItem;
    myStartItem=myEndItem;
    myEndItem=bufStartItem;
    QPointF pE_start=blockPoint2(myStartItem,type2);
    myStartItem=bufStartItem;
    myEndItem=bufEndItem;

    /*if(pS.x() < pE_back.x())
    {
        bool f1=(pS.y() < pE.y() && (type2 == up || type2 == back));
        bool f2=(pS.y() >= pE.y() && (type2 == down || type2 == back));
        if( (pS.y() < pE.y() && (type2 == up || type2 == back)) ||
                (pS.y() >= pE.y() && (type2 == down || type2 == back))
                )
        {
            currentP.setX(pE.x());
        }
        else
            currentP.setX(pE_back.x());
    }*/
    if(pE_back.x() < pS.x() && pS.x() < pE_start.x())
    {
        currentP.setX(pE_start.x() + pS.x()-myStartItem->pos().x()-widthRectangle/2.0);
    }
    return currentP;
}

QPointF Arrow2::firstY(QPointF currentP)
{
    QPointF pE  =blockPoint2(myEndItem,type2);
    if(currentP.x() <= pE.x())
        currentP.setY(pE.y());

    else
    {
        if(currentP.y()<pE.y())
        {
            currentP.setY( currentP.y() + (pE.y()-currentP.y()));
            if(type2 != up) currentP.setY(currentP.y() + heighRectangle/2.0);
            if(type2 == back)    currentP.setY(currentP.y() + heighRectangle/2.0);
        }
        else
        {
            currentP.setY( currentP.y() + (pE.y()-currentP.y()));
            if(type2 != down) currentP.setY(currentP.y() - heighRectangle/2.0);
            if(type2 == back)    currentP.setY(currentP.y() - heighRectangle/2.0);
        }
    }

    return currentP;
}
QPointF Arrow2::firstX(QPointF currentP)
{
    QPointF pE  =blockPoint2(myEndItem,type2);
    currentP.setX(pE.x());
    return currentP;
}

QPointF Arrow2::secondX(QPointF currentP)
{
    QPointF pE  =blockPoint2(myEndItem,type2);
    currentP.setY(pE.y());
    return currentP;
}

QList<QLineF>  Arrow2::makeArrow(QLineF lastLine)
{
    QList<QLineF> line;
    QPointF curP,bufP;
    //up
    if(type2 == up)
    {
        curP=lastLine.p2();
        bufP.setX(curP.x()-1-widthPen);
        bufP.setY(curP.y()-12);
        line<<QLineF(bufP,curP);
        bufP.setX(curP.x()+1+widthPen);
        bufP.setY(curP.y()-12);
        line<<QLineF(bufP,curP);
    }
    if(type2==back)
    {
        curP=lastLine.p2();
        bufP.setX(curP.x()-12);
        bufP.setY(curP.y()-1-widthPen);
        line<<QLineF(bufP,curP);
        bufP.setX(curP.x()-12);
        bufP.setY(curP.y()+1+widthPen);
        line<<QLineF(bufP,curP);
    }
    if(type2==down)
    {
        curP=lastLine.p2();
        bufP.setX(curP.x()-1-widthPen);
        bufP.setY(curP.y()+12);
        line<<QLineF(bufP,curP);
        bufP.setX(curP.x()+1+widthPen);
        bufP.setY(curP.y()+12);
        line<<QLineF(bufP,curP);
    }
    if(type2==front)
    {
        curP=lastLine.p1();
        bufP.setX(curP.x()-12);
        bufP.setY(curP.y()-1-widthPen);
        line<<QLineF(bufP,curP);
        bufP.setX(curP.x()-12);
        bufP.setY(curP.y()+1+widthPen);
        line<<QLineF(bufP,curP);
    }
    return line;
}


QList<Arrow2::parametrsArc> Arrow2::makeArk(QList<QLineF> &baseLines, qreal R)
{
    QList<parametrsArc> arc;
    parametrsArc bufArc;
    QMutableListIterator<QLineF> iter(baseLines);
    QLineF line1, line2;
    QPointF p1,p2;
    qreal r;
    int quarter;

    if(iter.hasNext())
        line1=iter.next();
    while(iter.hasNext())
    {
         line2=iter.next();
         //определим p1,p2
         r=R;
         quarter=1;
         if(line1.length()<R )  r=line1.length()/2.0;
         if(line2.length()<r)   r=line2.length()/2.0;
         if(line1.angle() == line2.angle()) r=0;

         //
         if(line1.angle() == 0 || line1.angle() == 180)
         {
             if(line1.x1()<line1.x2())
                 p1.setX(line1.x2()-r);
             else
                 p1.setX(line1.x2()+r);
             p1.setY(line1.y1());
         }
         else
         {
             p1.setX(line1.x1());
             if(line1.y1()<line1.y2())
                 p1.setY(line1.y2()-r);
             else
                 p1.setY(line1.y2()+r);
         }

         if(line2.angle() == 0 || line2.angle() == 180)
         {
             if(line2.x1()<line2.x2())
                 p2.setX(line2.x1()+r);
             else
                 p2.setX(line2.x1()-r);
             p2.setY(line2.y1());
         }
         else
         {
             p2.setX(line2.x1());
             if(line2.y1()<line2.y2())
                 p2.setY(line2.y1()+r);
             else
                 p2.setY(line2.y1()-r);
         }
         //определим четверть, в которой рсположен центр закругления
         if( p1.x()>p2.x() && p1.y()>p2.y() && line1.y2()>p2.y()    ||     p1.x()<p2.x() && p1.y()<p2.y() && line1.y2()>p1.y() )
             quarter=1;
         if( p1.x()<p2.x() && p1.y()>p2.y() && line1.y2()>p2.y()    ||     p1.x()>p2.x() && p1.y()<p2.y() && line1.y2()>p1.y())
             quarter=2;
         if( p1.x()<p2.x() && p1.y()<p2.y() && line1.x2()>p1.x()    ||     p1.x()>p2.x() && p1.y()>p2.y() && line1.x2()>p2.x())
             quarter=3;
         if( p1.x()<p2.x() && p1.y()>p2.y() && line1.x2()<p2.x()    ||     p1.x()>p2.x() && p1.y()<p2.y() && line1.x2()<p1.x() )
             quarter=4;
         //сделаем дугу
         if(quarter == 1)
         {
             bufArc.rect=QRectF(p1,p2);
             bufArc.startAngle=(-180)*16;
             bufArc.spanAngle=(90)*16;
             arc<<bufArc;
         }
         if(quarter == 2)
         {
             bufArc.rect=QRectF(p1,p2);
             bufArc.startAngle=0*16;
             bufArc.spanAngle=(-90)*16;
             arc<<bufArc;
         }
         if(quarter == 3)
         {
             bufArc.rect=QRectF(p1,p2);
             bufArc.startAngle=(0)*16;
             bufArc.spanAngle=(90)*16;
             arc<<bufArc;
         }
         if(quarter == 4)
         {
             bufArc.rect=QRectF(p1,p2);
             bufArc.startAngle=(180)*16;
             bufArc.spanAngle=(-90)*16;
             arc<<bufArc;
         }

         iter.previous();
         iter.previous();
         iter.next().setLength(iter.value().length()-r/2.0);
         iter.next();
         //магия
         QLineF bufLine=QLineF(line2.p2(),line2.p1());
         bufLine.setLength(bufLine.length()-r/2.0);
         iter.value().setPoints(bufLine.p2(),bufLine.p1());

         line1=line2;

    }
exit:
    return arc;
}

