import os
import platform
import sys
import re
import asyncio
import traceback

from functools import partial, wraps
from pxr import Sdf, Usd


# This piece of wrapper is borrowed from aiofiles, see following for details
# https://github.com/Tinche/aiofiles/blob/master/aiofiles/os.py
def wrap(func):
    @asyncio.coroutine
    @wraps(func)
    def run(*args, loop=None, executor=None, **kwargs):
        if loop is None:
            loop = asyncio.get_event_loop()
        pfunc = partial(func, *args, **kwargs)
        return loop.run_in_executor(executor, pfunc)

    return run


def _read_file(path):
    with open(path, "rb") as f:
        return f.read()


def _encode_content(content):
    if type(content) == str:
        payload = bytes(content.encode("utf-8"))
    elif type(content) != type(None):
        payload = bytes(content)
    else:
        payload = bytes()

    return payload


def _write_file(file, content):
    with open(file, "wb") as f:
        payload = _encode_content(content)
        f.write(payload)


def _open_layer(path):
    return Sdf.Layer.FindOrOpen(path)


def _open_stage(stage_path):
    return Usd.Stage.Open(stage_path)


def _transfer_layer_content(layer, target_layer):
    return target_layer.TransferContent(layer)


def _layer_save(layer):
    return layer.Save()


def _export_layer_to_string(layer):
    return layer.ExportToString()


def _re_find_all(regex, content):
    return re.findall(regex, content)


def _replace_all(s, old_text, new_text):
    if type(s) == bytes:
        s = s.decode()
    return s.replace(old_text, new_text)


aio_write_file = wrap(_write_file)
aio_read_file = wrap(_read_file)
aio_open_layer = wrap(_open_layer)
aio_export_layer_to_string = wrap(_export_layer_to_string)
aio_re_find_all = wrap(_re_find_all)
aio_replace_all = wrap(_replace_all)
aio_transfer_layer = wrap(_transfer_layer_content)
aio_open_stage = wrap(_open_stage)
aio_save_layer = wrap(_layer_save)
