/*
 * boardmodel.cpp - plugin
 * Copyright (C) 2010  Evgeny Khryukin
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include "boardmodel.h"

using namespace Chess;

BoardModel::BoardModel(Figure::GameType type, QObject *parent)
        : QAbstractTableModel(parent)
    , myMove(false)
    , waitForFigure(false)
    , check(false)
    , gameType_(Figure::NoGame)
    , gameState_(-1)
{
    setGameType(type);
    setHeaders();
}

void BoardModel::setHeaders()
{
    vHeader.clear();
    hHeader.clear();
    if(gameType_ == Figure::WhitePlayer) {
        vHeader << "8" << "7" << "6" << "5" << "4" << "3" << "2" << "1";
        hHeader << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
    }
    else {
        vHeader << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8";
        hHeader << "H" << "G" << "F" << "E" << "D" << "C" << "B" << "A";
    }
}

QVariant BoardModel::headerData ( int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole) {
                if (orientation == Qt::Horizontal) {
                        return hHeader.at(section);
        }
        else {
                        return vHeader.at(section);
                }
    }
    else
        return QVariant();
}

void BoardModel::setGameType(Figure::GameType type)
{
    gameType_ = type;
    if(type == Figure::WhitePlayer) {
        myMove = true;
    }
    else {
        myMove = false;
    }
}

Qt::ItemFlags BoardModel::flags ( const QModelIndex & /*index*/ ) const
{
    Qt::ItemFlags flags = Qt::NoItemFlags;
    flags |= Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    return flags;
}

int BoardModel::columnCount(const QModelIndex & /*parent*/) const
{
    return hHeader.size();
}

int BoardModel::rowCount(const QModelIndex &/* parent*/) const
{
    return vHeader.size();
}

QVariant BoardModel::data(const QModelIndex & i, int role) const
{
    QModelIndex index = i;
    if(!index.isValid())
        return QVariant();

    if(gameType_ == Figure::BlackPlayer)
        index = invert(index);

    if(role == Qt::BackgroundColorRole) {
        if(index == kingIndex() && isCheck())
            return QVariant(QColor("#9a0000"));
        int i = index.column() + index.row();
        if(i&1) {
            switch (gameState_) {
            case 1:
                return QVariant(QColor("green"));
            case 2:
                return QVariant(QColor("#b4ccff"));
            case 3:
                return QVariant(QColor("#9a0000"));
            default:
                return QVariant(QColor("#74440e"));
            }
        }
        else
            return QVariant(QColor("#ffedc2"));
    }
    else if(role == Qt::DisplayRole) {
        int x = index.column();
        int y = index.row();
        foreach(Figure *figure, whiteFigures_) {
            if(x == figure->positionX() && y == figure->positionY())
                return figure->getPixmap();
        }
        foreach(Figure *figure, blackFigures_) {
            if(x == figure->positionX() && y == figure->positionY())
                return figure->getPixmap();
        }
        return QVariant();
    }

    return QVariant();
}

void BoardModel::reset()
{
    gameState_ = 0;
    qDeleteAll(whiteFigures_);
    whiteFigures_.clear();
    qDeleteAll(blackFigures_);
    blackFigures_.clear();

    for(int i = 0; i < 8; i++) {
        Figure *whitePawn = new Figure(Figure::WhitePlayer, Figure::White_Pawn, i, 6, this);
        whiteFigures_.append(whitePawn);
    }
    Figure *whiteKing = new Figure(Figure::WhitePlayer, Figure::White_King, 4, 7, this);
    Figure *whiteQueen = new Figure(Figure::WhitePlayer, Figure::White_Queen, 3, 7, this);
    Figure *whiteBishop = new Figure(Figure::WhitePlayer, Figure::White_Bishop, 2, 7, this);
    Figure *whiteBishop2 = new Figure(Figure::WhitePlayer, Figure::White_Bishop, 5, 7, this);
    Figure *whiteKnight = new Figure(Figure::WhitePlayer, Figure::White_Knight, 1, 7, this);
    Figure *whiteKnight2 = new Figure(Figure::WhitePlayer, Figure::White_Knight, 6, 7, this);
    Figure *whiteCastle = new Figure(Figure::WhitePlayer, Figure::White_Castle, 0, 7, this);
    Figure *whiteCastle2 = new Figure(Figure::WhitePlayer, Figure::White_Castle, 7, 7, this);
    whiteFigures_.append(whiteKing);
    whiteFigures_.append(whiteQueen);
    whiteFigures_.append(whiteBishop);
    whiteFigures_.append(whiteBishop2);
    whiteFigures_.append(whiteKnight);
    whiteFigures_.append(whiteKnight2);
    whiteFigures_.append(whiteCastle);
    whiteFigures_.append(whiteCastle2);

    for(int i = 0; i < 8; i++) {
        Figure *blackPawn = new Figure(Figure::BlackPlayer, Figure::Black_Pawn, i, 1, this);
        blackFigures_.append(blackPawn);
    }
    Figure *blackKing = new Figure(Figure::BlackPlayer, Figure::Black_King, 4, 0, this);
    Figure *blackQueen = new Figure(Figure::BlackPlayer, Figure::Black_Queen, 3, 0, this);
    Figure *blackBishop = new Figure(Figure::BlackPlayer, Figure::Black_Bishop, 2, 0, this);
    Figure *blackBishop2 = new Figure(Figure::BlackPlayer, Figure::Black_Bishop, 5, 0, this);
    Figure *blackKnight = new Figure(Figure::BlackPlayer, Figure::Black_Knight, 1, 0, this);
    Figure *blackKnight2 = new Figure(Figure::BlackPlayer, Figure::Black_Knight, 6, 0, this);
    Figure *blackCastle = new Figure(Figure::BlackPlayer, Figure::Black_Castle, 0, 0, this);
    Figure *blackCastle2 = new Figure(Figure::BlackPlayer, Figure::Black_Castle, 7, 0, this);
    blackFigures_.append(blackKing);
    blackFigures_.append(blackQueen);
    blackFigures_.append(blackBishop);
    blackFigures_.append(blackBishop2);
    blackFigures_.append(blackKnight);
    blackFigures_.append(blackKnight2);
    blackFigures_.append(blackCastle);
    blackFigures_.append(blackCastle2);

    beginResetModel();
    endResetModel();
}

bool BoardModel::moveRequested(QModelIndex oldIndex, QModelIndex newIndex)
{
    if(!oldIndex.isValid() || !newIndex.isValid())
        return false;

    check = isCheck();
    Figure *figure = findFigure(oldIndex);
    if(figure) {
        if(figure->gameType() != gameType_ && myMove)
            return false;

        int x = newIndex.column();
        int y = newIndex.row();
        int move_ = canMove(figure, x, y);
        if(!move_)
            return false;
        Figure *newFigure = 0;
        if(move_ == 2) {  //kill figure
            newFigure = findFigure(newIndex);
            if(newFigure) {
                int tmpX = newFigure->positionX();
                int tmpY = newFigure->positionY();
                newFigure->setPosition(-1,-1);
                figure->setPosition(x, y);
                if(isCheck()) {
                    figure->setPosition(oldIndex.column(), oldIndex.row());
                    newFigure->setPosition(tmpX, tmpY);
                    return false;
                }
                emit figureKilled(newFigure);
            }
        }
        else if(move_ == 3) { //kill with pawn
            int tmpX = lastMove.figure->positionX();
            int tmpY = lastMove.figure->positionY();
            lastMove.figure->setPosition(-1,-1);
            figure->setPosition(x, y);
            if(isCheck()) {
                figure->setPosition(oldIndex.column(), oldIndex.row());
                lastMove.figure->setPosition(tmpX, tmpY);
                return false;
            }
            emit figureKilled(lastMove.figure);
        }
        else if(move_ == 4) {  //roc
            figure->setPosition(x, y);
            if(isCheck()) {
                figure->setPosition(oldIndex.column(), oldIndex.row());
                return false;
            }
            if(x == 6) {
                QModelIndex tmpIndex = createIndex(y,7);
                newFigure = findFigure(tmpIndex);
                newFigure->setPosition(5,y);
            }
            else if(x == 2) {
                QModelIndex tmpIndex = createIndex(y,0);
                newFigure = findFigure(tmpIndex);
                newFigure->setPosition(3,y);
            }
        }
        else { //move
            figure->setPosition(x, y);
            if(isCheck()) {
                figure->setPosition(oldIndex.column(), oldIndex.row());
                return false;
            }
        }

        figure->isMoved = true;
        lastMove.oldIndex = oldIndex;
        lastMove.newIndex = newIndex;
        lastMove.figure = figure;
        lastMove.killedFigure = newFigure;

        emit layoutChanged();

        if((figure->type() == Figure::White_Pawn && y == 0)
            || (figure->type() == Figure::Black_Pawn && y == 7) ) {
            if(myMove)
                emit needNewFigure(newIndex, figure->type() == Figure::White_Pawn ? "white" : "black");
            waitForFigure = true;
            tempIndex_ = oldIndex;
            return true;
        } else if(myMove)
            emit move(oldIndex.column(), 7-oldIndex.row(), newIndex.column(), 7-newIndex.row(), ""); //7- - for compatibility with tkabber

        moveTransfer();

        return true;
    }
    return false;
}

bool BoardModel::moveRequested(int oldX, int oldY, int newX, int newY) {
    return  moveRequested(createIndex(7-oldY, oldX), createIndex(7-newY, newX));//7- - for compatibility with tkabber
}

bool BoardModel::isYourFigure(const QModelIndex &index) const
{
    Figure *figure = findFigure(index);
    if(!figure)
        return false;

    return gameType_ == figure->gameType();
}

Figure *BoardModel::findFigure(QModelIndex index) const
{
    Figure *figure_ = 0;
    int x = index.column();
    int y = index.row();
    foreach(Figure *figure, whiteFigures_) {
        if(x == figure->positionX() && y == figure->positionY()) {
            figure_ = figure;
            break;
        }
    }
    if(!figure_) {
        foreach(Figure *figure, blackFigures_) {
            if(x == figure->positionX() && y == figure->positionY()) {
                figure_ = figure;
                break;
            }
        }
    }
    return figure_;
}

QModelIndex BoardModel::kingIndex() const
{
    if(gameType_ == Figure::WhitePlayer)
        return findFigure(Figure::White_King, gameType_);
    return findFigure(Figure::Black_King, gameType_);
}

QModelIndex BoardModel::findFigure(Figure::FigureType type, Figure::GameType game) const
{
    QModelIndex index;
    if(game == Figure::WhitePlayer) {
        foreach(Figure *figure, whiteFigures_) {
            if(type == figure->type()) {
                index = createIndex(figure->positionY(), figure->positionX());
            }
        }
    }
    else {
        foreach(Figure *figure, blackFigures_) {
            if(type == figure->type()) {
                index = createIndex(figure->positionY(), figure->positionX());
            }
        }
    }

    return index;
}

//return 0 - can't move;
//return 1 - can move;
//return 2 - kill someone;
//return 3 - strange pawn kill :)
//return 4 - roc
int BoardModel::canMove(Figure *figure, int newX, int newY) const
{
    int positionX_ = figure->positionX();
    int positionY_ = figure->positionY();
    bool isMoved = figure->isMoved;
    switch(figure->type()) {
        case Figure::White_Pawn:
        if(qAbs(newX - positionX_) > 1)
            return 0;

        if((positionY_ - newY) == 2 && !isMoved && newX == positionX_) {
            QModelIndex index = createIndex(positionY_-1, positionX_);
            if(findFigure(index))
                return 0;
            index = createIndex(newY,newX);
            if(findFigure(index))
                return 0;
            return 1;
        }

        if(positionY_ - newY == 1) {
            QModelIndex index = createIndex(newY, newX);
            Figure *f = findFigure(index);
            if(newX == positionX_) {
                if(!f)
                    return 1;
                else
                    return 0;
            }
            if(f && f->gameType() == Figure::BlackPlayer)
                return 2;
            if(lastMove.figure->type() == Figure::Black_Pawn
               && qAbs(lastMove.oldIndex.row() - lastMove.newIndex.row()) == 2
               && lastMove.oldIndex.row()+1 == newY
               && lastMove.oldIndex.column() == newX)
                return 3;
            return 0;
        }
        return 0;
        case Figure::Black_Pawn:
        if(qAbs(newX - positionX_) > 1)
            return 0;

        if((positionY_ - newY) == -2 && !isMoved && newX == positionX_) {
            QModelIndex index = createIndex(positionY_+1, positionX_);
            if(findFigure(index))
                return 0;
            index = createIndex(newY,newX);
            if(findFigure(index))
                return 0;
            return 1;
        }

        if(positionY_ - newY == -1) {
            QModelIndex index = createIndex(newY, newX);
            Figure *f = findFigure(index);
            if(newX == positionX_) {
                if(!f)
                    return 1;
                else
                    return 0;
            }
            if(f && f->gameType() == Figure::WhitePlayer)
                return 2;
            if(lastMove.figure->type() == Figure::White_Pawn
               && qAbs(lastMove.oldIndex.row() - lastMove.newIndex.row()) == 2
               && lastMove.oldIndex.row()-1 == newY
               && lastMove.oldIndex.column() == newX)
                return 3;
            return 0;
        }
        return 0;
        case Figure::White_Castle:
        if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) {
            if(positionX_-newX > 0) {
                for(int i = positionX_-newX-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_-i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newX-positionX_ > 0) {
                for(int i = newX-positionX_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_+i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(positionY_-newY > 0) {
                for(int i = positionY_-newY-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_-i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newY-positionY_ > 0) {
                for(int i = newY-positionY_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_+i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::Black_Castle:
        if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) {
            if(positionX_-newX > 0) {
                for(int i = positionX_-newX-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_-i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newX-positionX_ > 0) {
                for(int i = newX-positionX_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_+i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(positionY_-newY > 0) {
                for(int i = positionY_-newY-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_-i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newY-positionY_ > 0) {
                for(int i = newY-positionY_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_+i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::White_King:
        if(qAbs(newX - positionX_) < 2 && qAbs(newY - positionY_) < 2) {
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        if(check) {
            return 0;
        }
        if(!isMoved && newX == 6 && newY == 7) {
            Figure *figure_ = findFigure(createIndex(7, 7));
            if(!figure_) {
                return 0;
            }
            if(figure_->isMoved) {
                return 0;
            }
            figure_ = findFigure(createIndex(7,5));
            if(figure_) {
                return 0;
            }
            figure_ = findFigure(createIndex(7,6));
            if(figure_) {
                return 0;
            }
            figure->setPosition(5,7);
            foreach(Figure *figure_, blackFigures_) {
                if(figure_->positionX() != -1) {
                    if(canMove(figure_, 5,7)){
                        figure->setPosition(positionX_, positionY_);
                        return 0;
                    }
                }
            }
            return 4;
        }
        if(!isMoved && newX == 2 && newY == 7) {
            Figure *figure_ = findFigure(createIndex(7, 0));
            if(!figure_)
                return 0;
            if(figure_->isMoved)
                return 0;
            figure_ = findFigure(createIndex(7,3));
            if(figure_)
                return 0;
            figure_ = findFigure(createIndex(7,2));
            if(figure_)
                return 0;
            figure_ = findFigure(createIndex(7,1));
            if(figure_)
                return 0;
            figure->setPosition(3,7);
            foreach(Figure *figure_, blackFigures_) {
                if(figure_->positionX() != -1) {
                    if(canMove(figure_, 3,7)) {
                        figure->setPosition(positionX_, positionY_);
                        return 0;
                    }
                }
            }
            return 4;
        }
        return 0;
        case Figure::Black_King:
        if(qAbs(newX - positionX_) < 2 && qAbs(newY - positionY_) < 2) {
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        if(check)
            return 0;
        if(!isMoved && newX == 6 && newY == 0) {
            Figure *figure_ = findFigure(createIndex(0, 7));
            if(!figure_)
                return 0;
            if(figure_->isMoved)
                return 0;
            figure_ = findFigure(createIndex(0,5));
            if(figure_)
                return 0;
            figure_ = findFigure(createIndex(0,6));
            if(figure_)
                return 0;
            figure->setPosition(5,0);
            foreach(Figure *figure_, whiteFigures_) {
                if(figure_->positionX() != -1) {
                    if(canMove(figure_, 5,0)) {
                        figure->setPosition(positionX_, positionY_);
                        return 0;
                    }
                }
            }
            return 4;
        }
        if(!isMoved && newX == 2 && newY == 0) {
            Figure *figure_ = findFigure(createIndex(0, 0));
            if(!figure_)
                return 0;
            if(figure_->isMoved)
                return 0;
            figure_ = findFigure(createIndex(0,3));
            if(figure_)
                return 0;
            figure_ = findFigure(createIndex(0,2));
            if(figure_)
                return 0;
            figure_ = findFigure(createIndex(0,1));
            if(figure_)
                return 0;
            figure->setPosition(3,0);
            foreach(Figure *figure_, whiteFigures_) {
                if(figure_->positionX() != -1) {
                    if(canMove(figure_, 3,0)) {
                        figure->setPosition(positionX_, positionY_);
                        return 0;
                    }
                }
            }
            return 4;
        }
        return 0;
        case Figure::White_Bishop:
        if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) {
            if(newX-positionX_ > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            } else if(positionX_-newX > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::Black_Bishop:
        if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) {
            if(newX-positionX_ > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            } else if(positionX_-newX > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::White_Knight:
        if((qAbs(newX - positionX_) == 2 && qAbs(newY - positionY_) == 1)
            || (qAbs(newX - positionX_) == 1 && qAbs(newY - positionY_) == 2)) {
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::Black_Knight:
        if((qAbs(newX - positionX_) == 2 && qAbs(newY - positionY_) == 1)
            || (qAbs(newX - positionX_) == 1 && qAbs(newY - positionY_) == 2)) {
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::White_Queen:
        if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) {
            if(positionX_-newX > 0) {
                for(int i = positionX_-newX-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_-i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newX-positionX_ > 0) {
                for(int i = newX-positionX_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_+i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(positionY_-newY > 0) {
                for(int i = positionY_-newY-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_-i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newY-positionY_ > 0) {
                for(int i = newY-positionY_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_+i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) {
            if(newX-positionX_ > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            } else if(positionX_-newX > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::Black_Queen:
        if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) {
            if(positionX_-newX > 0) {
                for(int i = positionX_-newX-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_-i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newX-positionX_ > 0) {
                for(int i = newX-positionX_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_, positionX_+i);
                    if(findFigure(index))
                        return 0;
                }
            } else if(positionY_-newY > 0) {
                for(int i = positionY_-newY-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_-i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            } else if(newY-positionY_ > 0) {
                for(int i = newY-positionY_-1; i > 0; --i) {
                    QModelIndex index = createIndex(positionY_+i, positionX_);
                    if(findFigure(index))
                        return 0;
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) {
            if(newX-positionX_ > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = newX-positionX_-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_+i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            } else if(positionX_-newX > 0) {
                if(newY-positionY_ > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_+i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                } else if(positionY_-newY > 0) {
                    for(int i = positionX_-newX-1; i>0; --i){
                        QModelIndex index = createIndex(positionY_-i, positionX_-i);
                        if(findFigure(index))
                            return 0;
                    }
                }
            }
            Figure *figure_ = findFigure(createIndex(newY, newX));
            if(!figure_)
                return 1;
            else
                return 2;
        }
        return 0;
        case Figure::None:
        return 0;
        }
    return false;
}

QMultiMap<QModelIndex, int> BoardModel::availableMoves(Figure* figure) const
{
    QMultiMap<QModelIndex, int> map;
    for(int x = 0; x <= 7; x++) {
        for(int y = 0; y <= 7; y++) {
            if(isYourFigure(index(y,x)))
                continue;
            int move = canMove(figure, x, y);
            if(move) {
                map.insert(index(y,x), move);
            }
        }
    }
    return map;
}

int BoardModel::checkGameState()
{
    int state = 0;
    check = isCheck();
    if(gameType_ == Figure::WhitePlayer) {
        foreach(Figure *figure, whiteFigures_) {
            if(figure->positionX() != -1) {
                QMultiMap<QModelIndex, int> moves = availableMoves(figure);
                if(!moves.isEmpty()) {
                    QList<QModelIndex> ml = moves.keys();
                    foreach(QModelIndex index, ml) {
                        if(doTestMove(figure, index, moves.value(index))) {
                            return state; //in progress
                        }
                    }
                }
            }
        }
    } else {
        foreach(Figure *figure, blackFigures_) {
            if(figure->positionX() != -1) {
                QMultiMap<QModelIndex, int> moves = availableMoves(figure);
                if(!moves.isEmpty()) {
                    QList<QModelIndex> ml = moves.keys();
                    foreach(QModelIndex index, ml) {
                        if(doTestMove(figure, index, moves.value(index))) {
                            return state; //in progress
                        }
                    }
                }
            }
        }
    }

    state = isCheck() ? 2 : 1;
    return state;
}

bool BoardModel::doTestMove(Figure *figure, QModelIndex newIndex, int move)
{
    int oldX = figure->positionX();
    int oldY = figure->positionY();
    int x = newIndex.column();
    int y = newIndex.row();
    int tmpX;
    int tmpY;
    bool ch;
    Figure *newFigure = 0;
    switch(move) {
        case 1:
        figure->setPosition(x, y);
        ch = isCheck();
        figure->setPosition(oldX, oldY);
        return ch ? false : true;
        break;
        case 2:
        newFigure = findFigure(newIndex);
        if(newFigure) {
            tmpX = newFigure->positionX();
            tmpY = newFigure->positionY();
            newFigure->setPosition(-1,-1);
            figure->setPosition(x, y);
            ch = isCheck();
            figure->setPosition(oldX, oldY);
            newFigure->setPosition(tmpX, tmpY);
            return ch ? false : true;
        }
        return false;
        break;
         case 3:
        tmpX = lastMove.figure->positionX();
        tmpY = lastMove.figure->positionY();
        lastMove.figure->setPosition(-1,-1);
        figure->setPosition(x, y);
        ch = isCheck();
        figure->setPosition(oldX, oldY);
        lastMove.figure->setPosition(tmpX, tmpY);
        return ch ? false : true;
        break;
         case 4:
        figure->setPosition(x, y);
        ch = isCheck();
        figure->setPosition(oldX, oldY);
        return ch ? false : true;
        break;
        }
    return false;
}

bool BoardModel::isCheck() const
{
    if(!myMove)
        return false;

    bool check_ = false;
    QModelIndex king = kingIndex();
    int kingX = king.column();
    int kingY = king.row();
    if(gameType_ == Figure::WhitePlayer) {
        foreach(Figure* figure, blackFigures_) {
            if(figure->positionX() != -1) {
                if(canMove(figure, kingX, kingY) == 2) {
                    check_ = true;
                    break;
                }
            }
        }
    } else if(gameType_ == Figure::BlackPlayer) {
        foreach(Figure* figure, whiteFigures_) {
            if(figure->positionX() != -1) {
                if(canMove(figure, kingX, kingY) == 2) {
                    check_ = true;
                    break;
                }
            }
        }
    }
    return check_;
}

QModelIndex BoardModel::invert(QModelIndex index) const
{
    return createIndex(7 - index.row(), 7 - index.column());
}

void BoardModel::updateFigure(QModelIndex index, const QString& figure)
{
    Figure *oldFigure = findFigure(index);
    if( (gameType_ == Figure::WhitePlayer && myMove)
        || (gameType_ == Figure::BlackPlayer && !myMove) ) {
        if(figure == "queen") {
            oldFigure->setType(Figure::White_Queen);
        } else if(figure == "rook") {
            oldFigure->setType(Figure::White_Castle);
        } else if(figure == "bishop") {
            oldFigure->setType(Figure::White_Bishop);
        } else if(figure == "knight") {
            oldFigure->setType(Figure::White_Knight);
        }
    } else {
        if(figure == "queen") {
            oldFigure->setType(Figure::Black_Queen);
        } else if(figure == "rook") {
            oldFigure->setType(Figure::Black_Castle);
        } else if(figure == "bishop") {
            oldFigure->setType(Figure::Black_Bishop);
        } else if(figure == "knight") {
            oldFigure->setType(Figure::Black_Knight);
        }
    }
    if(myMove)
        emit move(tempIndex_.column(), 7-tempIndex_.row(), index.column(), 7-index.row(), figure); //7- - for compatibility with tkabber

    moveTransfer();
    waitForFigure = false;

    emit layoutChanged();
}

void BoardModel::moveTransfer()
{
    myMove = !myMove;
}

static inline Figure::FigureType rankFigure(int i)
{
    switch (i) {
        case 1:
        return Figure::White_Pawn;
        case 2:
        return Figure::White_Castle;
        case 3:
        return Figure::White_Bishop;
        case 4:
        return Figure::White_King;
        case 5:
        return Figure::White_Queen;
        case 6:
        return Figure::White_Knight;
        case 7:
        return Figure::Black_Pawn;
        case 8:
        return Figure::Black_Castle;
        case 9:
        return Figure::Black_Bishop;
        case 10:
        return Figure::Black_King;
        case 11:
        return Figure::Black_Queen;
        case 12:
        return Figure::Black_Knight;
        default:
        return Figure::None;
        }
    return Figure::None;
}

QString BoardModel::saveString() const
{
    QString save;
    foreach(Figure *figure, whiteFigures_) {
        save += QString("%1,%2,%3,%4;").arg(QString::number(figure->type()))
            .arg(QString::number(figure->positionY())).arg(QString::number(figure->positionX()))
            .arg(figure->isMoved ? QString::number(1) : QString::number(0));
    }
    foreach(Figure *figure, blackFigures_) {
        save += QString("%1,%2,%3,%4;").arg(QString::number(figure->type()))
            .arg(QString::number(figure->positionY())).arg(QString::number(figure->positionX()))
            .arg(figure->isMoved ? QString::number(1) : QString::number(0));
    }
    save += myMove ? QString::number(1) : QString::number(0);
    save += ";"+QString::number(gameType_)+";";
    return save;
}

void BoardModel::loadSettings(const QString& settings, bool myLoad)
{
    reset();

    QStringList figuresSettings = settings.split(";");
    foreach(Figure *figure, whiteFigures_) {
        if(!figuresSettings.isEmpty()) {
            QStringList set = figuresSettings.takeFirst().split(",");
            figure->setType(rankFigure(set.takeFirst().toInt()));
            figure->setPosition(set.takeFirst().toInt(),set.takeFirst().toInt());
            figure->isMoved = set.takeFirst().toInt();
        }
    }
    foreach(Figure *figure, blackFigures_) {
        if(!figuresSettings.isEmpty()) {
            QStringList set = figuresSettings.takeFirst().split(",");
            figure->setType(rankFigure(set.takeFirst().toInt()));
            figure->setPosition(set.takeFirst().toInt(),set.takeFirst().toInt());
            figure->isMoved = set.takeFirst().toInt();
        }
    }
    if(!figuresSettings.isEmpty())
        myMove = myLoad ? figuresSettings.takeFirst().toInt() : !figuresSettings.takeFirst().toInt();
    if(!figuresSettings.isEmpty()) {
        int i = figuresSettings.takeFirst().toInt();
        switch (i){
        case 1:
            gameType_ = myLoad ? Figure::WhitePlayer : Figure::BlackPlayer;
            break;
        case 2:
            gameType_ = myLoad ? Figure::BlackPlayer : Figure::WhitePlayer;
            break;
        default:
            gameType_ = Figure::NoGame;
            break;
        }
        setHeaders();
    }

    emit layoutChanged();
}

void BoardModel::updateView()
{
    emit layoutChanged();
}
