## vim:ts=4:et:nowrap
##
##---------------------------------------------------------------------------##
##
## PySol -- a Python Solitaire game
##
## Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
##
## 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 program; see the file COPYING.
## If not, write to the Free Software Foundation, Inc.,
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
##
## Markus F.X.J. Oberhumer
## <markus@oberhumer.com>
## http://www.oberhumer.com/pysol
##
##---------------------------------------------------------------------------##


# imports
import sys

# PySol imports
if sys.modules.has_key("pysoltk"):
    from gamedb import registerGame, GameInfo, GI
    from util import *
    from stack import *
    from game import Game
    from layout import Layout
    from hint import AbstractHint, DefaultHint, CautiousDefaultHint
    from pysoltk import MfxCanvasText, getFont


# /***********************************************************************
# // Talon
# ************************************************************************/

class Matriarchy_Waste(WasteStack):
    def updateText(self):
        WasteStack.updateText(self)
        if self.game.s.talon._updateMaxRounds():
            self.game.s.talon.updateText()


class Matriarchy_Talon(WasteTalonStack):
    DEAL = (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 11, 10, 9, 8, 7, 6, 5)

    def _updateMaxRounds(self):
        # recompute max_rounds
        old = self.max_rounds
        self.max_rounds = 11
        rows = self.game.s.rows
        for i in (0, 2, 4, 6):
            l1 =  len(rows[i+0].cards) + len(rows[i+8].cards)
            l2 =  len(rows[i+1].cards) + len(rows[i+9].cards)
            assert l1 + l2 <= 26
            if l1 + l2 == 26:
                self.max_rounds = self.max_rounds + 2
            elif l1 >= 13 or l2 >= 13:
                self.max_rounds = self.max_rounds + 1
        if self.max_rounds == 19:
            # game is won
            self.max_rounds = 18
        return old != self.max_rounds

    def canDealCards(self):
        if self._updateMaxRounds():
            self.updateText()
        if not self.cards and not self.game.s.waste.cards:
            return 0
        ncards = self.DEAL[self.round-1]
        assert ncards > 0
        return len(self.cards) >= ncards or self.round < self.max_rounds

    def dealCards(self, sound=0):
        # get number of cards to deal
        ncards = self.DEAL[self.round-1]
        assert ncards > 0
        # init
        waste = self.game.s.waste
        n = 0
        update_flags = 1
        # deal
        while n < ncards:
            # from self to waste
            while n < ncards:
                card = self.getCard()
                if not card:
                    break
                assert not card.face_up
                self.game.flipMove(self)
                self.game.moveMove(1, self, waste, frames=3, shadow=0)
                n = n + 1
            # turn from waste to self
            if n < ncards and len(waste.cards) > 0:
                assert len(self.cards) == 0
                assert self.round < self.max_rounds or update_flags == 0
                self.game.turnStackMove(waste, self, update_flags=update_flags)
                # do not update self.round anymore in this deal
                update_flags = 0
        assert self.round <= self.max_rounds
        assert n == ncards
        assert len(self.game.s.waste.cards) > 0
        # done
        return n

    def updateText(self):
        if self.game.preview > 1:
            return
        WasteTalonStack.updateText(self, update_rounds=0)
        ## t = "Round %d" % self.round
        t = "Round %d/%d" % (self.round, self.max_rounds)
        self.texts.rounds.config(text=t)
        t = "Deal %d" % self.DEAL[self.round-1]
        self.texts.misc.config(text=t)


# /***********************************************************************
# // Rows
# ************************************************************************/

class Matriarchy_UpRowStack(SS_RowStack):
    def __init__(self, x, y, game, suit):
        SS_RowStack.__init__(self, x, y, game, suit=suit,
                             base_rank=KING, mod=13, dir=1,
                             min_cards=1, max_cards=12)
        self.CARD_YOFFSET = -self.CARD_YOFFSET

    def getBottomImage(self):
        return self.game.app.images.getSuitBottom(self.cap.suit)


class Matriarchy_DownRowStack(SS_RowStack):
    def __init__(self, x, y, game, suit):
        SS_RowStack.__init__(self, x, y, game, suit=suit,
                             base_rank=QUEEN, mod=13, dir=-1,
                             min_cards=1, max_cards=12)

    def getBottomImage(self):
        return self.game.app.images.getSuitBottom(self.cap.suit)


# /***********************************************************************
# // Matriarchy
# ************************************************************************/

class Matriarchy(Game):
    Hint_Class = CautiousDefaultHint

    #
    # game layout
    #

    def createGame(self):
        # create layout
        l, s = Layout(self), self.s

        # set window
        # (set piles so that at least 2/3 of a card is visible with 12 cards)
        h = max(2*l.YS, (12-1)*l.YOFFSET + l.CH*2/3)
        self.setSize(10*l.XS+l.XM, h + l.YM + h)

        # create stacks
        center, c1, c2 = self.height / 2, h, self.height - h
        x, y = l.XM, c1 - l.CH
        for i in range(8):
            s.rows.append(Matriarchy_UpRowStack(x, y, self, i/2))
            x = x + l.XS
        x, y = l.XM, c2
        for i in range(8):
            s.rows.append(Matriarchy_DownRowStack(x, y, self, i/2))
            x = x + l.XS
        x, y = x + l.XS / 2, c1 - l.CH / 2 - l.CH
        tx = x + l.CW / 2
        s.waste = Matriarchy_Waste(x, y, self)
        l.createText(s.waste, "ss")
        y = c2 + l.CH / 2
        s.talon = Matriarchy_Talon(x, y, self, max_rounds=VARIABLE_REDEALS)
        l.createText(s.talon, "nn")
        s.talon.texts.rounds = MfxCanvasText(self.canvas,
                               tx, y + l.YS, anchor="n")
        s.talon.texts.misc = MfxCanvasText(self.canvas,
                               tx, center, anchor="center",
                               font=getFont("canvas_large"))

        # define stack-groups
        l.defaultStackGroups()

    #
    # game overrides
    #

    def _shuffleHook(self, cards):
        # move Queens to top of the Talon (i.e. first cards to be dealt)
        return self._shuffleHookMoveToTop(cards, lambda c: (c.rank == 11, c.suit), 8)

    def startGame(self):
        self.startDealSample()
        self.s.talon.dealRow(self.s.rows[8:])
        self.s.talon.dealCards()          # deal first cards to WasteStack

    def isGameWon(self):
        return len(self.s.talon.cards) == 0 and len(self.s.waste.cards) == 0

    def shallHighlightMatch(self, stack1, card1, stack2, card2):
        if card1.rank + card2.rank == QUEEN + KING:
            return 0
        return (card1.suit == card2.suit and
                ((card1.rank + 1) % 13 == card2.rank or (card2.rank + 1) % 13 == card1.rank))


# register the game
registerGame(GameInfo(17, Matriarchy, "Matriarchy",
                      GI.GT_2DECK_TYPE, 2, VARIABLE_REDEALS))

