'''
Created on 25.9.2010

@author: marekp
'''

import sys
import platform
import stat as statinfo

import fs.errors as errors
from fs.path import pathsplit
try:
    # For non-CPython or older CPython versions.
    # Simplejson also comes with C speedup module which
    # is not in standard CPython >=2.6 library.
    import simplejson as json
except ImportError:
    try:
        import json
    except ImportError:
        print("simplejson (http://pypi.python.org/pypi/simplejson/) required")
        raise

from .connection import Connection

python3 = int(platform.python_version_tuple()[0]) > 2

if python3:
    from urllib.error import HTTPError
else:
    from urllib.error import HTTPError

class TahoeUtil:
    def __init__(self, webapi):
        self.connection = Connection(webapi)

    def createdircap(self):
        return self.connection.post('/uri', params={'t': 'mkdir'}).read()

    def unlink(self, dircap, path=None):
        path = self.fixwinpath(path, False)
        self.connection.delete('/uri/%s%s' % (dircap, path))

    def info(self, dircap, path):
        path = self.fixwinpath(path, False)
        meta = json.load(self.connection.get('/uri/%s%s' % (dircap, path), {'t': 'json'}))
        return self._info(path, meta)

    def fixwinpath(self, path, direction=True):
        '''
            No, Tahoe really does not support file streams...
            This is ugly hack, because it is not Tahoe-specific.
            Should be move to middleware if will be any.
        '''
        if platform.system() != 'Windows':
            return path

        if direction and ':' in path:
                path = path.replace(':', '__colon__')
        elif not direction and '__colon__' in path:
                path = path.replace('__colon__', ':')
        return path

    def _info(self, path, data):
        if isinstance(data, list):
            type = data[0]
            data = data[1]
        elif isinstance(data, dict):
            type = data['type']
        else:
            raise errors.ResourceInvalidError('Metadata in unknown format!')

        if type == 'unknown':
            raise errors.ResourceNotFoundError(path)

        info = {'name': str(self.fixwinpath(path, True)),
                'type': type,
                'size': data.get('size', 0),
                'ctime': None,
                'uri': data.get('rw_uri', data.get('ro_uri'))}
        if 'metadata' in data:
            info['ctime'] = data['metadata'].get('ctime')

        if info['type'] == 'dirnode':
            info['st_mode'] = 0o777 |  statinfo.S_IFDIR
        else:
            info['st_mode'] = 0o644

        return info

    def list(self, dircap, path=None):
        path = self.fixwinpath(path, False)

        data = json.load(self.connection.get('/uri/%s%s' % (dircap, path), {'t': 'json'}))

        if len(data) < 2 or data[0] != 'dirnode':
            raise errors.ResourceInvalidError('Metadata in unknown format!')

        data = data[1]['children']
        for i in list(data.keys()):
            x = self._info(i, data[i])
            yield x

    def mkdir(self, dircap, path):
        path = self.fixwinpath(path, False)
        path = pathsplit(path)

        self.connection.post("/uri/%s%s" % (dircap, path[0]), data={'t': 'mkdir', 'name': path[1]})

    def move(self, dircap, src, dst):
        if src == '/' or dst == '/':
            raise errors.UnsupportedError("Too dangerous operation, aborting")

        src = self.fixwinpath(src, False)
        dst = self.fixwinpath(dst, False)

        src_tuple = pathsplit(src)
        dst_tuple = pathsplit(dst)

        if src_tuple[0] == dst_tuple[0]:
            # Move inside one directory
            self.connection.post("/uri/%s%s" % (dircap, src_tuple[0]), data={'t': 'rename',
                                        'from_name': src_tuple[1], 'to_name': dst_tuple[1]})
            return

        # Move to different directory. Firstly create link on dst, then remove from src
        try:
            self.info(dircap, dst)
        except errors.ResourceNotFoundError:
            pass
        else:
            self.unlink(dircap, dst)

        uri = self.info(dircap, src)['uri']
        self.connection.put("/uri/%s%s" % (dircap, dst), data=uri, params={'t': 'uri'})
        if uri != self.info(dircap, dst)['uri']:
            raise errors.OperationFailedError('Move failed')

        self.unlink(dircap, src)
