#!/usr/bin/env python


# Copyright 2004-2005 PyTom <pytom@bishoujo.us>
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
# This file contains functions that load and save the game state.

from pickle import dumps, loads, HIGHEST_PROTOCOL
import cStringIO
import zipfile
import time
import os
import re

import renpy


# This is used as a quick and dirty way of versioning savegame
# files.
savegame_suffix = renpy.savegame_suffix

def debug_dump(prefix, o, seen):

    if isinstance(o, (int, str, float, bool)):
        print prefix, o
        return

    if id(o) in seen:
        print prefix, "@%x" % id(o), type(o)
        return

    seen[id(o)] = True

    if isinstance(o, tuple):
        print prefix, "("
        for i in o:
            debug_dump(prefix + "  ", i, seen)
        print prefix, ")"

    elif isinstance(o, list):
        print prefix, "["
        for i in o:
            debug_dump(prefix + "  ", i, seen)
        print prefix, "]"

    elif isinstance(o, dict):
        print prefix, "{"
        for k, v in o.iteritems():
            print prefix, repr(k), "="
            debug_dump(prefix + "    ", v, seen)
        print prefix, "}"

    elif isinstance(o, renpy.style.Style):
        print "<style>"
    
    elif hasattr(o, "__dict__"):

        ignored = getattr(o, "nosave", [ ])

        print prefix, repr(o), "{{"
        for k, v in vars(o).iteritems():
            if k in ignored:
                continue

            print prefix, repr(k), "="
            debug_dump(prefix + "    ", v, seen)
        print prefix, "}}"

    else:
        print prefix, repr(o)

    

def save(filename, extra_info=''):
    """
    Saves the game in the given filename. This will save the game
    along with a screnshot and the given extra_info, which is just
    serialized.

    It's expected that a screenshot will be taken (with
    renpy.take_screenshot) before this is called.
    """

    filename = filename + savegame_suffix

    try:
        os.unlink(renpy.config.savedir + "/" + filename)
    except:
        pass


    renpy.game.log.freeze()


    try:
        zf = zipfile.ZipFile(renpy.config.savedir + "/" + filename,
                             "w", zipfile.ZIP_DEFLATED)

        # Screenshot.
        zf.writestr("screenshot.tga", renpy.game.interface.get_screenshot())

        # Extra info.
        zf.writestr("extra_info", extra_info)

        # print
        # print "Debug Dump!"
        # if os.environ['RENPY_DEBUG_DUMP']:

        # renpy.config.debug = True
        # debug_dump("", renpy.game.log, { })

        # The actual game.
        zf.writestr("log", dumps(renpy.game.log, HIGHEST_PROTOCOL))

        zf.close()
    finally:              
        renpy.game.log.discard_freeze()



def saved_games(regexp=r'.'):
    """
    This scans the savegames that we know about and returns
    information about them. Specifically, it returns tuple containing
    a savelist and the filename of the newest save file (or None if no
    save file exists).

    The savelist, in turn, is a list of tuples, with each tuple containing
    the filename of the saved game, a Displayable containing a screenshot,
    and a string giving the extra data of that save.

    The regexp matches at the start of the filename, and filters the list.
    """

    files = os.listdir(renpy.config.savedir)
    files.sort()
    files = [ i for i in files if i.endswith(savegame_suffix) and re.match(regexp, i) ]

    if not files:
        newest = None
    else:
        datefiles = [ (os.stat(renpy.config.savedir + "/" + i).st_mtime, i) for i in files ]
        datefiles.sort()
        newest = datefiles[-1][1]
        newest = newest[:-len(savegame_suffix)]

    saveinfo = { }

    for f in files:

        try:

            zf = zipfile.ZipFile(renpy.config.savedir + "/" + f, "r")
            extra_info = zf.read("extra_info")
            sio = cStringIO.StringIO(zf.read("screenshot.tga"))
            zf.close()

            screenshot = renpy.display.image.UncachedImage(sio, "screenshot.tga", False)

            f = f[:-len(savegame_suffix)]

            saveinfo[f] = screenshot, extra_info

        except:
            if renpy.config.debug:
                raise Exception

    if newest not in saveinfo:
        newest = None

    return saveinfo, newest

def can_load(filename):
    """
    Returns true if we can load the given savegame file, False otherwise.
    """

    try:
        zf = zipfile.ZipFile(renpy.config.savedir + "/" + filename + savegame_suffix, "r")
        zf.close()
        return True
    except:
        return False
    

def load(filename):
    """
    Loads the game from the given file. This function never returns.
    """
    
    zf = zipfile.ZipFile(renpy.config.savedir + "/" + filename + savegame_suffix, "r")
    log = loads(zf.read("log"))
    zf.close()

    log.unfreeze(label="after_load")
