import cPickle
import pickle
import numpy as np
import os
import time
import warnings
import sys
from pylearn2.utils.string_utils import preprocess
from cPickle import BadPickleGet
io = None
hdf_reader = None


def load(filepath, recurse_depth=0):
    try:
        import joblib
        joblib_available = True
    except ImportError:
        joblib_available = False
    if recurse_depth == 0:
        filepath = preprocess(filepath)

    if filepath.endswith('.npy'):
        return np.load(filepath)

    if filepath.endswith('.mat'):
        global io
        if io is None:
            import scipy.io
            io = scipy.io
        try:
            return io.loadmat(filepath)
        except NotImplementedError, nei:
            if str(nei).find('HDF reader') != -1:
                global hdf_reader
                if hdf_reader is None:
                    import h5py
                    hdf_reader = h5py
                return hdf_reader.File(filepath)
            else:
                raise
        #this code should never be reached
        assert False

    def exponential_backoff():
        if recurse_depth > 9:
            print ('Max number of tries exceeded while trying to open ' +
                   filepath)
            print 'attempting to open via reading string'
            f = open(filepath, 'rb')
            lines = f.readlines()
            f.close()
            content = ''.join(lines)
            return cPickle.loads(content)
        else:
            nsec = 0.5 * (2.0 ** float(recurse_depth))
            print "Waiting " + str(nsec) + " seconds and trying again"
            time.sleep(nsec)
            return load(filepath, recurse_depth + 1)

    try:
        if not joblib_available:
            with open(filepath, 'rb') as f:
                obj = cPickle.load(f)
        else:
            obj = joblib.load(filepath)
        return obj
    except BadPickleGet, e:
        print ('Failed to open ' + str(filepath) +
               ' due to BadPickleGet with exception string ' + str(e))

        return exponential_backoff()
    except EOFError, e:
        print ('Failed to open ' + str(filepath) +
               ' due to EOFError with exception string ' + str(e))

        return exponential_backoff()
    except ValueError, e:
        print ('Failed to open ' + str(filepath) +
               ' due to ValueError with string ' + str(e))

        return exponential_backoff()
    except Exception, e:
        #assert False
        exc_str = str(e)
        if len(exc_str) > 0:
            import pdb
            tb = pdb.traceback.format_exc()
            raise Exception("Couldn't open '" + str(filepath) +
                            "' due to: " + str(type(e)) + ', ' + str(e) +
                            ". Orig traceback:\n" + tb)
        else:
            print ("Couldn't open '" + str(filepath) +
                   "' and exception has no string. Opening it again outside "
                   "the try/catch so you can see whatever error it prints on "
                   "its own.")
            f = open(filepath, 'rb')
            obj = cPickle.load(f)
            f.close()
            return obj


def save(filepath, obj):
    filepath = preprocess(filepath)
    try:
        _save(filepath, obj)
    except RuntimeError, e:
        """ Sometimes for large theano graphs, pickle/cPickle exceed the
            maximum recursion depth. This seems to me like a fundamental
            design flaw in pickle/cPickle. The workaround I employ here
            is the one recommended to someone who had a similar problem
            on stackexchange:

            http://stackoverflow.com/questions/2134706/hitting-maximum-recursion-depth-using-pythons-pickle-cpickle

            Obviously this does not scale and could cause a crash
            but I don't see another solution short of writing our
            own implementation of pickle.
        """
        if str(e).find('recursion') != -1:
            warnings.warn('pylearn2.utils.save encountered the following '
                          'error: ' + str(e) +
                          '\nAttempting to resolve this error by calling ' +
                          'sys.setrecusionlimit and retrying')
            old_limit = sys.getrecursionlimit()
            try:
                sys.setrecursionlimit(50000)
                _save(filepath, obj)
            finally:
                sys.setrecursionlimit(old_limit)


def _save(filepath, obj):
    try:
        import joblib
        joblib_available = True
    except ImportError:
        joblib_available = False
    if filepath.endswith('.npy'):
        np.save(filepath, obj)
        return
    assert filepath.endswith('.pkl')
    save_dir = os.path.dirname(filepath)
    if not os.path.exists(save_dir) or not os.path.isdir(save_dir):
        raise IOError("save path %s is not an existing directory" % save_dir)
    elif not os.access(save_dir, os.W_OK):
        raise IOError("permission error creating %s" % filepath)
    try:
        if joblib_available:
            joblib.dump(obj, filepath)
        else:
            with open(filepath, 'wb') as filehandle:
                cPickle.dump(obj, filehandle)
    except Exception, e:
        print "cPickle has failed to write an object to "+filepath
        if str(e).find('maximum recursion depth exceeded') != -1:
            raise
        try:
            print 'retrying with pickle'
            f = open(filepath, "wb")
            pickle.dump(obj, f)
            f.close()
        except Exception, e2:
            try:
                f.close()
            except:
                pass
            if str(e) == '' and str(e2) == '':
                print (
                    'neither cPickle nor pickle could write to ' + str(filepath)
                )
                print (
                    'moreover, neither of them raised an exception that '
                    'can be converted to a string'
                )
                print (
                    'now re-attempting to write with cPickle outside the '
                    'try/catch loop so you can see if it prints anything '
                    'when it dies'
                )
                f = open(filepath, 'wb')
                cPickle.dump(obj, f)
                f.close()
                print ('Somehow or other, the file write worked once '
                       'we quit using the try/catch.')
            else:
                if str(e2) == 'env':
                    raise

                import pdb
                tb = pdb.traceback.format_exc()

                raise Exception(str(obj) +
                                ' could not be written to '+
                                str(filepath) +
                                ' by cPickle due to '+str(e)+
                                ' nor by pickle due to '+str(e2)+
                                '. \nTraceback '+ tb)
        print ('Warning: ' + str(filepath) +
               ' was written by pickle instead of cPickle, due to '
               + str(e) +
               ' (perhaps your object is really big?)')


def clone_via_serialize(obj):
    str = cPickle.dumps(obj)
    return cPickle.loads(str)


def to_string(obj):
    return cPickle.dumps(obj)


def mkdir(filepath):
    try:
        os.makedirs(filepath)
    except:
        print ("couldn't make directory '" + str(filepath) +
               "', maybe it already exists")

@@ -4747,42 +4747,197 @@
     
-if not os.path.exists(save_dir) or
+# Handle current working directory case.%0A    if save_dir == '':%0A        save_dir = '.'%0A    if not os.path.exists(save_dir):%0A        os.makedirs(save_dir)%0A    if os.path.exists(save_dir) and
  not
@@ -5002,26 +5002,21 @@
  %25s 
-is not an existing
+exists, not a
  dir

Handle save_paths with no directory component