# -*- coding: utf-8 -*-
import operator

from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt


#noinspection PyClassHasNoInit
class PlayerModelState:
    AVAILABLE = 0
    PLAYING = 1
    AFK = 2
    NSTATES = 3


class PlayerModel(QtCore.QAbstractTableModel):
    STATE = 0
    PLAYER = 1
    PING = 2
    OPPONENT = 3
    IGNORE = 4
    COUNTRY = 5
    OPPONENT_COUNTRY = 6
    N_COLS = 7

    DEFAULT_SORT = PLAYER

    # state, player, ping, opponent, ignore
    displayColumns = ["", "Player", "Ping", "Opponent", ""]
    N_DISPLAY_COLS = len(displayColumns)

    sortableColumns = [PLAYER, PING, OPPONENT]

    def __init__(self, controller):
        super(PlayerModel, self).__init__()
        self.controller = controller
        # [state, player, ping, opponent, ignored, country, opponent_country]
        self.players = []
        self.lastSort = PlayerModel.DEFAULT_SORT
        self.lastSortOrder = QtCore.Qt.AscendingOrder
        controller.sigPlayerStateChange.connect(self.reloadPlayers)
        controller.sigPlayersLoaded.connect(self.reloadPlayers)
        # TODO: optimize to only update challenge column?
        controller.sigChallengeDeclined.connect(self.reloadPlayers)
        # This is very heavy-handed for handling the CLI add/remove changes
        controller.sigIgnoreAdded.connect(self.reloadPlayers)
        controller.sigIgnoreRemoved.connect(self.reloadPlayers)

    # noinspection PyMethodMayBeStatic
    def columnCount(self, QModelIndex_parent=None, *args, **kwargs):
        return PlayerModel.N_DISPLAY_COLS

    def data(self, modelIndex, role=None):
        if not modelIndex.isValid():
            return None

        row = modelIndex.row()
        col = modelIndex.column()

        if role == Qt.DisplayRole:
            if col in [PlayerModel.PLAYER, PlayerModel.PING, PlayerModel.OPPONENT]:
                return self.players[row][col]
        elif role == Qt.ToolTipRole and col in [PlayerModel.PLAYER, PlayerModel.OPPONENT]:
            name = self.players[row][col]
            if name in self.controller.players:
                if self.controller.players[name].city:
                    return self.controller.players[name].country + ', ' + self.controller.players[name].city
                else:
                    return self.controller.players[name].country
        elif role == Qt.CheckStateRole and col == PlayerModel.IGNORE:
            return self.players[row][col]
        elif role == Qt.DecorationRole:
            return self.dataIcon(row, col)
        elif role == Qt.TextAlignmentRole:
            if col == PlayerModel.PING:
                return Qt.AlignRight | Qt.AlignVCenter
        elif role == Qt.TextColorRole:
            if col in [PlayerModel.PLAYER, PlayerModel.OPPONENT]:
                name = self.players[row][col]
                if name == 'ponder':
                    return QtGui.QBrush(QtGui.QColor(Qt.red))

    def dataIcon(self, row, col):
        icon_path = None
        if col == PlayerModel.PLAYER:
            icon_path = ':/flags/' + self.players[row][PlayerModel.COUNTRY] + '.png'
        elif col == PlayerModel.OPPONENT:
            icon_path = ':/flags/' + self.players[row][PlayerModel.OPPONENT_COUNTRY] + '.png'
        elif col == PlayerModel.STATE:
            val = self.players[row][col]
            if self.controller.challenged:
                if self.players[row][PlayerModel.PLAYER] == self.controller.challenged:
                    icon_path = ':/images/sword-no.png'
                elif val == PlayerModelState.PLAYING:
                    icon_path = ':/images/eye.png'
                elif val == PlayerModelState.AFK:
                    icon_path = ':/assets/face-sleeping.png'
            else:
                if val == PlayerModelState.AVAILABLE:
                    icon_path = ':/images/sword.png'
                elif val == PlayerModelState.PLAYING:
                    icon_path = ':/images/eye.png'
                elif val == PlayerModelState.AFK:
                    icon_path = ':/assets/face-sleeping.png'
        if icon_path:
            return QtGui.QIcon(icon_path)

    def flags(self, index):
        if index.isValid():
            if index.column() == PlayerModel.IGNORE:
                return Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsEditable
            else:
                return Qt.ItemIsEnabled
        return super(PlayerModel, self).flags(index)

    def getPlayerStat(self, player, stat):
        if player in self.controller.players:
            if hasattr(self.controller.players[player], stat):
                return getattr(self.controller.players[player], stat)
        return ''

    # noinspection PyMethodMayBeStatic
    def headerData(self, section, Qt_Orientation, role=None):
        if role == Qt.DisplayRole and Qt_Orientation == Qt.Horizontal and 0 <= section < PlayerModel.N_DISPLAY_COLS:
            return PlayerModel.displayColumns[section]
        if role == Qt.DecorationRole and Qt_Orientation == Qt.Horizontal:
            if section == PlayerModel.IGNORE:
                return QtGui.QIcon(':/assets/face-ignore.png')

    def onCellClicked(self, index):
        col = index.column()
        row = index.row()
        if col == PlayerModel.STATE:
            modified = False
            if self.controller.challenged == self.players[row][PlayerModel.PLAYER]:
                self.controller.sendCancelChallenge()
                modified = True
            elif self.players[row][PlayerModel.STATE] == PlayerModelState.AVAILABLE:
                self.controller.sendChallenge(self.players[row][PlayerModel.PLAYER])
                modified = True
            elif self.players[row][PlayerModel.STATE] == PlayerModelState.PLAYING:
                self.controller.sendSpectateRequest(self.players[row][PlayerModel.PLAYER])
                modified = True
            if modified:
                idx1 = self.createIndex(0, PlayerModel.STATE)
                idx2 = self.createIndex(len(self.players) - 1, PlayerModel.STATE)
                # noinspection PyUnresolvedReferences
                self.dataChanged.emit(idx1, idx2)

    def onCellDoubleClicked(self, index):
        col = index.column()
        row = index.row()
        if col == PlayerModel.PLAYER:
            modified = False
            if self.controller.challenged == self.players[row][PlayerModel.PLAYER]:
                self.controller.sendCancelChallenge()
                modified = True
            elif self.players[row][PlayerModel.STATE] == PlayerModelState.AVAILABLE:
                self.controller.sendChallenge(self.players[row][PlayerModel.PLAYER])
                modified = True
            elif self.players[row][PlayerModel.STATE] == PlayerModelState.PLAYING:
                self.controller.sendSpectateRequest(self.players[row][PlayerModel.PLAYER])
                modified = True
            if modified:
                idx1 = self.createIndex(0, PlayerModel.STATE)
                idx2 = self.createIndex(len(self.players) - 1, PlayerModel.STATE)
                # noinspection PyUnresolvedReferences
                self.dataChanged.emit(idx1, idx2)

    # noinspection PyUnusedLocal
    def reloadPlayers(self, *args):
        self.players = []
        for p in self.controller.available.keys():
            ignored = (p in self.controller.ignored) and Qt.Checked or Qt.Unchecked
            self.players.append([PlayerModelState.AVAILABLE,
                                 p, self.getPlayerStat(p, 'ping'),
                                 '', ignored,
                                 self.getPlayerStat(p, 'cc'), ''])
        for p, p2 in self.controller.playing.items():
            ignored = (p in self.controller.ignored) and Qt.Checked or Qt.Unchecked
            self.players.append([PlayerModelState.PLAYING,
                                 p, self.getPlayerStat(p, 'ping'),
                                 p2, ignored,
                                 self.getPlayerStat(p, 'cc'),
                                 self.getPlayerStat(p2, 'cc')])
        for p in self.controller.awayfromkb.keys():
            ignored = (p in self.controller.ignored) and Qt.Checked or Qt.Unchecked
            self.players.append([PlayerModelState.AFK,
                                 p, self.getPlayerStat(p, 'ping'),
                                 '', ignored,
                                 self.getPlayerStat(p, 'cc'), ''])
        self.sort(self.lastSort, self.lastSortOrder)
        # idx1 = self.createIndex(0, 0)
        # idx2 = self.createIndex(len(self.players) - 1, PlayerModel.N_DISPLAY_COLS-1)
        # self.dataChanged.emit(idx1, idx2)

    def rowCount(self, QModelIndex_parent=None, *args, **kwargs):
        return len(self.players)

    def setData(self, modelIndex, value, role=None):
        row = modelIndex.row()
        col = modelIndex.column()
        if role == Qt.CheckStateRole and col == PlayerModel.IGNORE:
            self.players[row][col] = value
            # noinspection PyUnresolvedReferences
            self.dataChanged.emit(modelIndex, modelIndex)
            player = self.players[row][PlayerModel.PLAYER]
            if value == Qt.Checked:
                self.controller.addIgnore(player)
            else:
                self.controller.removeIgnore(player)
        return True

    def sort(self, col, order=None):
        if col in PlayerModel.sortableColumns:
            reverse = False
            if order == QtCore.Qt.DescendingOrder:
                reverse = True
            self.lastSort = col
            self.lastSortOrder = order
            getter = operator.itemgetter(col)
            if col in [PlayerModel.PLAYER, PlayerModel.OPPONENT]:
                keyfunc = lambda x: getter(x).lower()
            else:
                keyfunc = getter
            self.emit(QtCore.SIGNAL("layoutAboutToBeChanged()"))
            self.players = sorted(self.players, key=keyfunc, reverse=reverse)
            self.players = sorted(self.players, key=operator.itemgetter(PlayerModel.STATE))
            self.emit(QtCore.SIGNAL("layoutChanged()"))