import psp2d

def show_loading():
  lloading = psp2d.Image('images/loading.png')
  lx = (480 - lloading.width) / 2
  ly = (272 - lloading.height) / 2
  psp2d.Screen().blit(lloading, 0, 0, -1, -1, lx, ly, True)
  psp2d.Screen().swap()
  
show_loading()

import vs_screen
from vs_card import *
from vs_buttons import *
from solitaire import *
import select

class tmain(vs_screen.tscreen):
  static_buffer = None
  background = None
  card_selection = None
  font = None
  draw_button = None
  game_state = None
  show_selection = True
  undo = []
  redo = []
  xs = None
  ys = None
  show_saved = 0
  saved_image = None
  
  def get_super(self):
    return vs_screen.tscreen

  def __init__(self):
    self.super.__init__(self)
    self.xs = 80
    self.ys = 20
    self.static_buffer = psp2d.Image(480, 272)
    self.background_image = psp2d.Image('images/background.png')
    self.saved_image = psp2d.Image('images/saved.png')
    self.font = psp2d.Font('images/font_arial_10_white.png')
    self.draw_button = tdraw_button(self.static_buffer, self.font)
    self.game_state = tgame_state()
    self.card_selection = tcard_selection()
    self.init_stacks()

  def init_stacks(self):
    ly = self.ys
    ld = 48

    self.game_state.deal_stack.x = self.xs + ld
    self.game_state.deal_stack.y = ly
    self.game_state.deal_stack.top_only = True

    self.game_state.spades_stack.x = self.xs + ld * 3
    self.game_state.spades_stack.y = ly
    self.game_state.spades_stack.top_only = True
    
    self.game_state.clubs_stack.x = self.xs + ld * 4
    self.game_state.clubs_stack.y = ly
    self.game_state.clubs_stack.top_only = True
    
    self.game_state.diamonds_stack.x = self.xs + ld * 5
    self.game_state.diamonds_stack.y = ly
    self.game_state.diamonds_stack.top_only = True
    
    self.game_state.hearts_stack.x = self.xs + ld * 6
    self.game_state.hearts_stack.y = ly
    self.game_state.hearts_stack.top_only = True
    
    # main game stacks
    self.game_state.stacks = []
    lx = self.xs
    ly = ly + 58
    for i in range(0, 7):
      lstack = tstack()
      lstack.x = lx
      lstack.y = ly
      self.game_state.stacks.append(lstack)
      lx = lx + ld

  def init_deck(self):
    self.game_state.deck.clear()
    lsuits = [suits.spades, suits.clubs, suits.diamonds, suits.hearts]
    for lsuit in lsuits:
      for lvalue in range(0, 13):
        self.game_state.deck.add(lsuit, lvalue, False)
    self.game_state.deck.shuffle()

  def init_deal(self):
    self.init_deck()
    self.undo = []
    self.redo = []
    
    self.game_state.deal_stack.items = []
    self.game_state.spades_stack.items = []
    self.game_state.clubs_stack.items = []
    self.game_state.diamonds_stack.items = []
    self.game_state.hearts_stack.items = []
    
    for lstack in self.game_state.stacks:
      lstack.items = []

    lcount = 1
    for lstack in self.game_state.stacks:
      lstack.items = []
      
      for i in range(0, lcount - 1):
        lcard = self.game_state.deck.items.pop()
        lstack.add_existing(lcard)
        
      lcard = self.game_state.deck.items.pop()
      lcard.face_up = True
      lstack.add_existing(lcard)
      
      lcount = lcount + 1

    self.game_state.selected_stack_index = 0
    self.game_state.selected_index = len(self.selected_stack.items) - 1
    
    self.update_static()
    
  def deal(self):
    if len(self.game_state.deck.items) > 0 \
        or len(self.game_state.deal_stack.items) > 0:
      self.copy_undo()
      
      if len(self.game_state.deck.items) == 0:
        self.game_state.deck.items = self.game_state.deal_stack.items
        self.game_state.deal_stack.items = []
      
      self.show_selection = False
      try:
        limage = tcard_images.back
        lx = self.xs
        ly = self.ys
        lframes = 5
        lstack = self.game_state.deal_stack;

        lcount = min(self.game_state.game_type + 1, len(self.game_state.deck.items))
        for lframe in range(0, lcount):
          lcard = self.game_state.deck.items.pop()
          lcard.face_up = True
          ldx = lstack.x
          ldy = lstack.y
          lxchange = ((ldx - lx) / float(lframes))
          lychange = ((ldy - ly) / float(lframes))
          for lframe_index in range(0, lframes + 1):
            lcard.x = lx + (lxchange * float(lframe_index))
            lcard.y = ly + (lychange * float(lframe_index))
            self.screen.blit(self.static_buffer)
            lcard.update(self.screen)
            self.screen.swap()
          lstack.items.append(lcard)
          lcard.update(self.static_buffer)
      finally:
        self.show_selection = True
        self.game_state.selected_index = len(self.selected_stack.items) - 1
        self.update_static()

  def play_deal_stack(self):
    ldeal_card = self.game_state.deal_stack.last_card
    if ldeal_card != None:
      lcard = self.selected_stack.last_card
      lplay = False
      if lcard == None:
        if ldeal_card.value == tcards.king:
          lplay = True
      elif lcard.value == ldeal_card.value + 1 and ldeal_card.opposite(lcard):
        lplay = True
      if lplay:
        self.copy_undo()
        self.game_state.deal_stack.items.pop()
        self.selected_stack.items.append(ldeal_card)
        self.game_state.selected_index = len(self.selected_stack.items) - 1
        self.selected_stack.calculate_positions()
        self.update_static()

  def meld_deal_stack(self):
    ldeal_card = self.game_state.deal_stack.last_card
    if ldeal_card != None:
      if ldeal_card.suit == tsuits.spades:
        lstack = self.game_state.spades_stack
      elif ldeal_card.suit == tsuits.clubs:
        lstack = self.game_state.clubs_stack
      elif ldeal_card.suit == tsuits.diamonds:
        lstack = self.game_state.diamonds_stack
      else:
        lstack = self.game_state.hearts_stack
        
      lstack.top_only = True
      lstack_card = lstack.last_card
      lplay = False
      if lstack_card == None:
        if ldeal_card.value == tcards.ace:
          lplay = True
      elif ldeal_card.value == lstack_card.value + 1:
        lplay = True
      if lplay:
        self.copy_undo()
        self.game_state.deal_stack.items.pop()
        lstack.items.append(ldeal_card)
        self.game_state.selected_index = len(self.selected_stack.items) - 1
        lstack.calculate_positions()
        self.check_stacks()
        self.update_static()
        
  def meld_card(self):
    if len(self.selected_stack.items) > 0:
      lcard = self.selected_stack.last_card
      if lcard != None:
        if lcard.suit == tsuits.spades:
          lstack = self.game_state.spades_stack
        elif lcard.suit == tsuits.clubs:
          lstack = self.game_state.clubs_stack
        elif lcard.suit == tsuits.diamonds:
          lstack = self.game_state.diamonds_stack
        else:
          lstack = self.game_state.hearts_stack

        lstack.top_only = True
        lstack_card = lstack.last_card;
        lplay = False
        if lstack_card == None:
          if lcard.value == tcards.ace:
            lplay = True
        elif lcard.value == lstack_card.value + 1:
          lplay = True
        if lplay:
          self.copy_undo()
          self.selected_stack.items.pop()
          lstack.items.append(lcard)
          self.game_state.selected_index = len(self.selected_stack.items) - 1
          lstack.calculate_positions()
          self.check_stacks()
          self.update_static()

  @property
  def selected_stack(self):
    return self.game_state.stacks[self.game_state.selected_stack_index]

  @property
  def selected_item(self):
    try:
      litem = self.selected_stack.items[self.game_state.selected_index]
    except:
      litem = None
    return litem

  def select_left(self):
    lselected_index = self.game_state.selected_stack_index
    lselected_index = lselected_index - 1
    if lselected_index >= 0:
      self.game_state.selected_stack_index = lselected_index
      self.game_state.selected_index = len(self.selected_stack.items) - 1

  def select_right(self):
    lselected_index = self.game_state.selected_stack_index
    lselected_index = lselected_index + 1
    if lselected_index < len(self.game_state.stacks):
      self.game_state.selected_stack_index = lselected_index
      self.game_state.selected_index = len(self.selected_stack.items) - 1

  def select_up(self):
    lselected_index = self.game_state.selected_index - 1
    if lselected_index >= 0:
      lselected = self.selected_item
      lnew = self.selected_stack.items[lselected_index]
      if lnew.face_up and lselected.opposite(lnew) and lnew.value == lselected.value + 1:
        self.game_state.selected_index = lselected_index;

  def select_down(self):
    lselected_index = self.game_state.selected_index + 1
    if lselected_index < len(self.selected_stack.items):
      self.game_state.selected_index = lselected_index;

  def move_left(self):
    if len(self.selected_stack.items) > 0:
      lselected_index = self.game_state.selected_stack_index
      lnew_index = lselected_index
      while True:
        lnew_index = lnew_index - 1
        if lnew_index < 0:
          break
        else:
          lcard = self.game_state.stacks[lnew_index].last_card
          if lcard == None:
              if self.selected_item.value == tcards.king:
                break
          elif lcard.value == self.selected_item.value + 1 and self.selected_item.opposite(lcard):
            break
      if lnew_index >= 0:
        self.copy_undo()
        lnew_card_index = len(self.game_state.stacks[lnew_index].items)
        litems = self.game_state.stacks[lselected_index].items
        self.game_state.stacks[lselected_index].items = litems[0:self.game_state.selected_index]
        self.game_state.stacks[lnew_index].items = self.game_state.stacks[lnew_index].items + litems[self.game_state.selected_index:len(litems)]
        self.game_state.selected_stack_index = lnew_index
        self.game_state.selected_index = lnew_card_index
        self.check_stacks()
        self.update_static()

  def move_right(self):
    if len(self.selected_stack.items) > 0:
      lselected_index = self.game_state.selected_stack_index
      lnew_index = lselected_index
      while True:
        lnew_index = lnew_index + 1
        if lnew_index >= len(self.game_state.stacks):
          break
        else:
          lcard = self.game_state.stacks[lnew_index].last_card
          if lcard == None:
              if self.selected_item.value == tcards.king:
                break
          elif lcard.value == self.selected_item.value + 1 and self.selected_item.opposite(lcard):
            break
      if lnew_index < len(self.game_state.stacks):
        self.copy_undo()
        lnew_card_index = len(self.game_state.stacks[lnew_index].items)
        litems = self.game_state.stacks[lselected_index].items
        self.game_state.stacks[lselected_index].items = litems[0:self.game_state.selected_index]
        self.game_state.stacks[lnew_index].items = self.game_state.stacks[lnew_index].items + litems[self.game_state.selected_index:len(litems)]
        self.game_state.selected_stack_index = lnew_index
        self.game_state.selected_index = lnew_card_index
        self.check_stacks()
        self.update_static()

  def check_stacks(self):
    for lstack in self.game_state.stacks:
      self.check_stack_complete(lstack)
      lcard = lstack.last_card
      if lcard != None:
        lcard.face_up = True
    self.check_game_complete()
        
  def check_stack_complete(self, pstack):
    llast_index = len(pstack.items) - 1
    if llast_index >= cards.king - 1:
      lok = True
      lsuit = pstack.items[llast_index].suit
      for lindex in range(cards.ace, cards.king + 1):
        lcard = pstack.items[llast_index - lindex]
        if not lcard.face_up or lcard.suit != lsuit or lcard.value != lindex:
          lok = False
          break
      if lok:
        self.complete_stack(pstack)

  def check_game_complete(self):
    if self.game_complete:
      self.show_select(False, True)
      
  @property
  def game_complete(self):
    lcomplete = True
    for lstack in self.game_state.stacks:
      if len(lstack.items) > 0:
        lcomplete = False
        break
    return lcomplete
        
  def button_down(self, pbuttons):
    if buttons.cross in pbuttons:
      if buttons.left in pbuttons:
        self.move_left()
      elif buttons.right in pbuttons:
        self.move_right()
      elif buttons.up in pbuttons:
        self.meld_card()
      elif buttons.down in pbuttons:
        self.play_deal_stack()
    elif buttons.circle in pbuttons:
      if buttons.right in pbuttons:
        self.meld_deal_stack()
      elif buttons.down in pbuttons:
        self.play_deal_stack()
      elif buttons.up in pbuttons:
        self.meld_card()
    elif buttons.left_trigger in pbuttons:
      self.do_undo()
    elif buttons.right_trigger in pbuttons:
      self.do_redo()
    elif buttons.triangle in pbuttons:
      self.deal()
    elif buttons.select in pbuttons:
      self.show_select(True, False)
    elif buttons.start in pbuttons:
      self.save_game()
    
  def button_up(self, pbuttons):
    pass

  def button_press(self, pbuttons):
    if (not buttons.cross in pbuttons) and (not buttons.circle in pbuttons) :
      if buttons.left in pbuttons:
        self.select_left()
      if buttons.right in pbuttons:
        self.select_right()
      if buttons.up in pbuttons:
        self.select_up()
      if buttons.down in pbuttons:
        self.select_down()
        
  def calculate_positions(self):
    for lstack in self.game_state.stacks:
      lstack.calculate_positions()

  def update_static(self):
    self.static_buffer.blit(self.background_image, 0, 0, -1, -1, 0, 0, False)
    self.update_stacks()
    self.update_buttons()

  def update(self):
    self.screen.blit(self.static_buffer)
    self.update_animation()
    self.super.update(self)
      
  def update_stacks(self):
    if self.game_state.deck.empty:
      self.static_buffer.blit(tcard_images.empty, 0, 0, -1, -1, self.xs, self.ys, True)
    else:
      self.static_buffer.blit(tcard_images.back, 0, 0, -1, -1, self.xs, self.ys, True)
      self.font.drawText(self.static_buffer \
          , self.xs + 35, self.ys + 3 \
          , `self.game_state.deck.count`)

    self.game_state.deal_stack.update(self.static_buffer)
    if not self.game_state.deal_stack.empty:
      self.font.drawText(self.static_buffer \
          , self.game_state.deal_stack.x + 35, self.game_state.deal_stack.y + 3 \
          , `self.game_state.deal_stack.count`)
          
    self.game_state.spades_stack.update(self.static_buffer)
    self.game_state.clubs_stack.update(self.static_buffer)
    self.game_state.diamonds_stack.update(self.static_buffer)
    self.game_state.hearts_stack.update(self.static_buffer)
    
    for lstack in self.game_state.stacks:
      lstack.calculate_positions()
      lstack.update(self.static_buffer)

  def show_select(self, pallow_continue, pcompleted):
    lselect = select.tselect(self.game_state.game_type, pallow_continue, pcompleted)
    lselect.show()
    if lselect.quit:
      self.close()
    elif pcompleted or lselect.restart:
      self.game_state.game_type = lselect.game_type
      self.init_deal()
      
  def update_buttons(self):
    lx = 190
    ly = 236
    self.draw_button.draw_button(lx, ly, buttons.select, 'Menu')
    lx = lx + 60
    self.draw_button.draw_button(lx, ly, buttons.start, 'Save')
    
  def update_animation(self):
    if self.show_selection:
      if len(self.selected_stack.items) > 0:
        lselected = self.selected_item
        lx = lselected.x
        ly = lselected.y
      else:
        lx = self.selected_stack.x
        ly = self.selected_stack.y
        
      try:
        self.card_selection.update(self.screen, lx - 7, ly - 8)
      except:
        pass
        
    if self.show_saved > 0:
      lx = (480 - self.saved_image.width) / 2
      ly = (272 - self.saved_image.height) / 2
      self.screen.blit(self.saved_image, 0, 0, -1, -1, lx, ly, True)
      self.show_saved = self.show_saved - 1

  def show(self):
    if self.load_game():
      self.show_select(True, False)
      self.update_static()
    else:
      self.show_select(False, False)
    self.super.show(self)
    
  def copy_undo(self):
    self.redo = []
    self.undo.append(self.game_state.duplicate())
    
  def copy_redo(self):
    self.redo.append(self.game_state.duplicate())
    
  def do_undo(self):
    if len(self.undo) > 0:
      self.copy_redo()
      self.game_state = self.undo.pop()
      self.update_static()
    
  def do_redo(self):
    if len(self.redo) > 0:
      self.undo.append(self.game_state.duplicate())
      self.game_state = self.redo.pop()
      self.update_static()

  def load_game(self):
    try:
      self.game_state.load_from_file('save_game.dat')
      self.game_state.calculate_positions()
      return True
    except:
      return False
    
  def save_game(self):
    self.show_saved = 50
    self.update()
    self.game_state.save_to_file('save_game.dat')
    
    
