#include <QtGui>

#include "diagramscene.h"
#include "arrow.h"
#include "arrow2.h"
#include "mainwindow.h"
//! [0]

DiagramScene::DiagramScene(QMenu *itemMenu, QObject *parent, QMenu *sceneMenu)
    : QGraphicsScene(parent)
{
    myItemMenu = itemMenu;
    myMode = MoveItem;
    myItemType = DiagramItem::Step;
	mySceneMenu = sceneMenu;
    line = 0;
    textItem = 0;
    myItemColor = Qt::white;
    myTextColor = Qt::black;
    myLineColor = Qt::black;

	id=1;
        numberB=0;
	fl = 0; fl1 = 0; altFlag = 0; comFlag = 0;
}
//! [0]

//! [1]
void DiagramScene::setLineColor(const QColor &color)
{
    myLineColor = color;

    if (isItemChange(Arrow2::Type))
    {
        Arrow2 *item =
            qgraphicsitem_cast<Arrow2 *>(selectedItems().first());
        item->setColor(myLineColor);
        update();
    }
}
//! [1]

//! [2]
void DiagramScene::setTextColor(const QColor &color)
{
    myTextColor = color;
    if (isItemChange(DiagramTextItem::Type)) {
        DiagramTextItem *item =
            qgraphicsitem_cast<DiagramTextItem *>(selectedItems().first());
        item->setDefaultTextColor(myTextColor);
    }
}
//! [2]

//! [3]
void DiagramScene::setItemColor(const QColor &color)
{
    myItemColor = color;
    if (isItemChange(DiagramItem::Type)) {
        DiagramItem *item =
            qgraphicsitem_cast<DiagramItem *>(selectedItems().first());
        item->setBrush(myItemColor);
    }
}
//! [3]

//! [4]
void DiagramScene::setFont(const QFont &font)
{
    myFont = font;

    if (isItemChange(DiagramTextItem::Type)) {
        QGraphicsTextItem *item =
            qgraphicsitem_cast<DiagramTextItem *>(selectedItems().first());
        //At this point the selection can change so the first selected item might not be a DiagramTextItem
        if (item)
            item->setFont(myFont);
    }
}
//! [4]

void DiagramScene::setMode(Mode mode)
{
    myMode = mode;
}

void DiagramScene::setItemType(DiagramItem::DiagramType type)
{
    myItemType = type;
}

//! [5]
void DiagramScene::editorLostFocus(DiagramTextItem *item)
{
    QTextCursor cursor = item->textCursor();
    cursor.clearSelection();
    item->setTextCursor(cursor);

    if (item->toPlainText().isEmpty()) {
        removeItem(item);
        item->deleteLater();
    }
    if (!item->toPlainText().isEmpty() && comFlag == 1)
	{
        item->setID(id);
        id++;
		emit textInserted(qgraphicsitem_cast<DiagramTextItem *>(item), textPos);
		comFlag = 0;
	}
}
//! [5]

//Добавление подвешенной стрелки "управление"
void DiagramScene::arrowDown2(QGraphicsItem * par)
{
        DiagramItem *item;
        Arrow2::TypeIn flyinTypeArrow;
        item = new DiagramItem(DiagramItem::DiagramType::Conditional, myItemMenu, par);
        item->setID(id);
        id++;
        item->setBrush(myItemColor);
        addItem(item);

        //вот тут рисовать стрелку
        //par - основной блок; item - маленький блок
        DiagramItem *startItem =item;
        QPointF ppp=startItem->pos();
        DiagramItem *endItem = qgraphicsitem_cast<DiagramItem *>(par);

        QPointF p = endItem->pos();
        QPointF p2;
        p2.setX(p.x());
        p2.setY(p.y() -40);

        Arrow2 *arrow = new Arrow2(startItem, endItem, p2, 0, true, Arrow2::TypeIn::up);

        arrow->setID(id);
        id++;
    arrow->setColor(myLineColor);
    startItem->addArrow(arrow);
    endItem->addArrow(arrow);
    arrow->setZValue(-1000.0);

    addItem(arrow);
    arrow->updatePosition();
                int startId =  startItem->id();
                int endId = endItem->id();
                int arrId = arrow->getID();
                emit arrInserted(arrow, startId, endId, arrId, p2, 1);
}

//Добавление подвешенной стрелки "ресурсы"
void DiagramScene::arrowUp2(QGraphicsItem * par)
{
        DiagramItem *item;
        Arrow2::TypeIn flyinTypeArrow;
        item = new DiagramItem(DiagramItem::DiagramType::Conditional, myItemMenu, par);
        item->setID(id);
        id++;
    item->setBrush(myItemColor);
    addItem(item);

        //вот тут рисовать стрелку
        //par - основной блок; item - маленький блок
        DiagramItem *startItem =item;
        QPointF ppp=startItem->pos();
        DiagramItem *endItem = qgraphicsitem_cast<DiagramItem *>(par);

        QPointF p = endItem->pos();
        QPointF p2;
        p2.setX(p.x());
        p2.setY(p.y() +40);

        Arrow2 *arrow = new Arrow2(startItem, endItem, p2, 0, true, Arrow2::TypeIn::down);

        arrow->setID(id);
        id++;
    arrow->setColor(myLineColor);
    startItem->addArrow(arrow);
    endItem->addArrow(arrow);
    arrow->setZValue(-1000.0);

    addItem(arrow);
    arrow->updatePosition();
                int startId =  startItem->id();
                int endId = endItem->id();
                int arrId = arrow->getID();
                emit arrInserted(arrow, startId, endId, arrId, p2, 1);
}

//Добавление подвешенной стрелки "вход"
void DiagramScene::arrowBack2(QGraphicsItem * par)
{
        DiagramItem *item;
        Arrow2::TypeIn flyinTypeArrow;
        item = new DiagramItem(DiagramItem::DiagramType::Conditional, myItemMenu, par);
        item->setID(id);
        id++;
    item->setBrush(myItemColor);
    addItem(item);

        //вот тут рисовать стрелку
        //par - основной блок; item - маленький блок
        DiagramItem *startItem =item;
        QPointF ppp=startItem->pos();
        DiagramItem *endItem = qgraphicsitem_cast<DiagramItem *>(par);

        QPointF p = endItem->pos();
        QPointF p2;
        p2.setX(p.x()-90);
        p2.setY(p.y());

        Arrow2 *arrow = new Arrow2(startItem, endItem, p2, 0, true, Arrow2::TypeIn::back);

        arrow->setID(id);
        id++;
    arrow->setColor(myLineColor);
    startItem->addArrow(arrow);
    endItem->addArrow(arrow);
    arrow->setZValue(-1000.0);

    addItem(arrow);
    arrow->updatePosition();
                int startId =  startItem->id();
                int endId = endItem->id();
                int arrId = arrow->getID();
                emit arrInserted(arrow, startId, endId, arrId, p2, 1);
}

//Добавление подвешенной стрелки "выход"
void DiagramScene::arrowFront2(QGraphicsItem * par)
{
        DiagramItem *item;
        Arrow2::TypeIn flyinTypeArrow;
        item = new DiagramItem(DiagramItem::DiagramType::Conditional, myItemMenu, par);
        item->setID(id);
        id++;
    item->setBrush(myItemColor);
    addItem(item);

        //вот тут рисовать стрелку
        //par - основной блок; item - маленький блок
        DiagramItem *startItem =item;
        QPointF ppp=startItem->pos();
        DiagramItem *endItem = qgraphicsitem_cast<DiagramItem *>(par);

        QPointF p = endItem->pos();
        QPointF p2;
        p2.setX(p.x()-90);
        p2.setY(p.y());

        Arrow2 *arrow = new Arrow2(endItem, endItem, p2, 0, true, Arrow2::TypeIn::front);

        arrow->setID(id);
        id++;
    arrow->setColor(myLineColor);
    startItem->addArrow(arrow);
    endItem->addArrow(arrow);
    arrow->setZValue(-1000.0);

    addItem(arrow);
    arrow->updatePosition();
                int startId =  startItem->id();
                int endId = endItem->id();
                int arrId = arrow->getID();
                emit arrInserted(arrow, startId, endId, arrId, p2, 1);
}

//! [6]
void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (mouseEvent->button() != Qt::LeftButton)
        return;

 //   dragStartPosition = mouseEvent->scenePos();
	//QGraphicsItem *graphicsItem = itemAt(dragStartPosition);
    	//dragItem = qgraphicsitem_cast<DiagramItem *>(graphicsItem);
    
     DiagramItem *item;
	QPointF tmp;
	QGraphicsItem *tmpitem;
	QGraphicsItem *graphicsItem;
	DiagramTextItem *textItem;
    switch (myMode) {
        case InsertItem:
            item = new DiagramItem(myItemType, myItemMenu);
			item->setID(id);
			id++;
                        item->setNumberB(numberB);
                        item->setNumber(item, numberB);
                        numberB++;
            item->setBrush(myItemColor);
            addItem(item);
            item->setPos(mouseEvent->scenePos());
			emit itemInserted(item);
			break;
//! [6] //! [7]
        case InsertLine:
            line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(),
                                        mouseEvent->scenePos()));
            line->setPen(QPen(myLineColor, 2));
            addItem(line);
			dragStartPosition = mouseEvent->scenePos();
            break;
//! [7] //! [8]
        case InsertText:
            textItem = new DiagramTextItem();
            textItem->setFont(myFont);
            textItem->setFlag(QGraphicsItem::ItemIsMovable);
            textItem->setFlag(QGraphicsItem::ItemIsSelectable);
            textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
            textItem->setZValue(1000.0);
            connect(textItem, SIGNAL(lostFocus(DiagramTextItem*)),
                    this, SLOT(editorLostFocus(DiagramTextItem*)));
            connect(textItem, SIGNAL(selectedChange(QGraphicsItem*)),
                    this, SIGNAL(itemSelected(QGraphicsItem*)));
            addItem(textItem);
            textItem->setDefaultTextColor(myTextColor);
            textItem->setPos(mouseEvent->scenePos());
            //textItem->setID(id);
            //id++;
			if (comFlag == 0)
			{
				textPos = mouseEvent->scenePos();
				comFlag = 1;
			}
            myMode = MoveItem;
            break;
        case MoveItem:
			dragStartPosition = mouseEvent->scenePos();
			graphicsItem = itemAt(dragStartPosition);
			dragItem = qgraphicsitem_cast<DiagramItem *>(graphicsItem);
            if (dragItem != 0)
                isAnythingSelected = 1;
            else
                isAnythingSelected = 0;
			if (itemAt(dragStartPosition) != 0 && dragItem != 0)
			{
				if (mouseEvent->modifiers() == Qt::AltModifier)
				{
					emit retItem(dragItem->id());

					newItem = new DiagramItem(myItemType, myItemMenu);
					newItem->setID(id);
					id++;
					addItem(newItem);
					newItem->setPos(dragStartPosition);
                    newItem->setNumberB(numberB);
                    newItem->setNumber(newItem, numberB);
                    numberB++;
					emit itemInserted(newItem);
		    		textItem = new DiagramTextItem(newItem);
				    textItem->setPos(-90.0,-40.0);
					textItem->setTextWidth(180);
					textItem->setPlainText(dragItem->comment());
					emit itemCommInserted(dragItem->comment(), newItem->id());

					altFlag = 1;
				}
				else if(mouseEvent->modifiers() != Qt::AltModifier)
				{
					emit retItem(dragItem->id());
					fl = 1; fl1=0;
                }
			}
//! [8] //! [9]
    default:
        ;
    }
    QGraphicsScene::mousePressEvent(mouseEvent);

}
//! [9]

//! [10]
void DiagramScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (myMode == InsertLine && line != 0) {
        QLineF newLine(line->line().p1(), mouseEvent->scenePos());
        line->setLine(newLine);
    }
    else if (myMode == MoveItem)
    {
		if (mouseEvent->modifiers() == Qt::AltModifier) 
		{
			if(altFlag == 1)
			{
				newItem->setPos(mouseEvent->scenePos());
			}
		}
		if (mouseEvent->modifiers() != Qt::AltModifier && fl == 1)
		{
			fl1=1;
			dragStartPosition = dragItem->pos();
		}
        QGraphicsScene::mouseMoveEvent(mouseEvent);
    }
}
//! [10]

//! [11]
void DiagramScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{

    QPointF pEnd;
    QPointF newPoint;
    if (line != 0 && myMode == InsertLine) {
        QList<QGraphicsItem *> startItems = items(line->line().p1());
        if (startItems.count() && startItems.first() == line)
            startItems.removeFirst();
        QList<QGraphicsItem *> endItems = items(line->line().p2()); 
        if (endItems.count() && endItems.first() == line)
        {
            pEnd=line->line().p2();
            endItems.removeFirst();
        }

        removeItem(line);
        delete line;
//! [11] //! [12]

		DiagramItem *startItem; DiagramItem *endItem;
		QGraphicsItem *graphicsItem = itemAt(dragStartPosition);
		startItem = qgraphicsitem_cast<DiagramItem *>(graphicsItem);
		graphicsItem = itemAt(mouseEvent->scenePos());
		endItem = qgraphicsitem_cast<DiagramItem *>(graphicsItem);
        if (startItem != 0 && endItem != 0 && startItem != endItem)
		{
            Arrow2 *arrow = new Arrow2(startItem, endItem, mouseEvent->scenePos());
                arrow->setID(id);
                id++;
            arrow->setColor(myLineColor);
            startItem->addArrow(arrow);
            endItem->addArrow(arrow);
            arrow->setZValue(-1000.0);

            addItem(arrow);
            arrow->updatePosition();
			int startId =  startItem->id();
			int endId = endItem->id();
	        int arrId = arrow->getID();
            emit arrInserted(arrow, startId, endId, arrId, pEnd, 0);
        }
        //emit itemMoved();
    }
//! [12] //! [13]
    line = 0;
        //emit itemMoved();
    if(myMode==MoveItem)
    {
		if (altFlag == 1 )
		{//сохраняем состояние
            newPoint = mouseEvent->scenePos();
            if (newPoint.x() < MIN_WIDTH + widthRectangle / 2.0 + 5) {newPoint.setX(MIN_WIDTH + widthRectangle / 2.0 + 5);}
            if (newPoint.y() < MIN_HEIGHT + heighRectangle / 2.0 + 55) {newPoint.setY(MIN_HEIGHT + heighRectangle / 2.0 + 55);}
            if (newPoint.x() > MAX_WIDTH - widthRectangle / 2.0 - 5) {newPoint.setX(MAX_WIDTH - widthRectangle / 2.0 - 5);}
            if (newPoint.y() > MAX_HEIGHT - heighRectangle / 2.0 - 55) {newPoint.setY(MAX_HEIGHT - heighRectangle / 2.0 - 55);}

            emit itemChangeKoords(newItem, newPoint);
			altFlag = 0;
        }
		if (fl == 1 && fl1 == 1)//Чтоб блок не "прыгал", когда жмакаешь не по центру 
		{						//Но сохранялся, если его перемещают
            newPoint = dragStartPosition;
            if (newPoint.x() < MIN_WIDTH + widthRectangle / 2.0 + 5) {newPoint.setX(MIN_WIDTH + widthRectangle / 2.0 + 5);}
            if (newPoint.y() < MIN_HEIGHT + heighRectangle / 2.0 + 55) {newPoint.setY(MIN_HEIGHT + heighRectangle / 2.0 + 55);}
            if (newPoint.x() > MAX_WIDTH - widthRectangle / 2.0 - 5) {newPoint.setX(MAX_WIDTH - widthRectangle / 2.0 - 5);}
            if (newPoint.y() > MAX_HEIGHT - heighRectangle / 2.0 - 55) {newPoint.setY(MAX_HEIGHT - heighRectangle / 2.0 - 55);}

            emit itemChangeKoords(dragItem, newPoint);
			fl = 0; fl1 = 0;
		}
        fl = 0;
		altFlag =0;
    }
    QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
//! [13]

//! [14]
bool DiagramScene::isItemChange(int type)
{
    foreach (QGraphicsItem *item, selectedItems()) {
        if (item->type() == type)
		{
			//DiagramItem *item1;
			//item1=qgraphicsitem_cast<DiagramItem *>(item);
			//int id = item1->id();
			//QPointF point = 
            return true;
		}
    }
    return false;
}
//! [14]
void DiagramScene::setID(int ID)
{
	id = ID+1;
}

void DiagramScene::setNumberB(int num)
{
        numberB = num+1;
}
void DiagramScene::setItem(DiagramItem *item)
{
	if (item->id() > 0)
		dragItem = item;
}
//если нажали правой кнопкой на сцену - вызвалась контекстная менюшка
void DiagramScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
	QGraphicsItem* item = itemAt(event->scenePos());
	DiagramItem* ditem = qgraphicsitem_cast<DiagramItem *>(item);
	if (ditem == 0)	//если действительно жмакнул на пустую сцену, где нет блока
	{
		clearSelection();
		mySceneMenu->exec(event->screenPos());
	}
	else		//если жмакнул на блок - вызовется меню блока
	{
		ditem->contextMenu(event);
	}
}
