# coding: utf-8
import os, sys, json,time 
import chardet,psutil

from base import *


def format_path(path):
    return path.replace('\\', '/')

def to_path(path):
    return path.replace('/', '\\')

# 获取根目录列表
def get_paths(path, flist):
    try:
        path = path.replace('\\', '/')
        path = os.path.dirname(path)
        if not path in flist:
            flist.append(path)
            get_paths(path, flist)
    except:
        pass

# 取文件指定尾行数
def GetNumLines(path, num, p=1):
    pyVersion = sys.version_info[0]
    max_len = 1024 * 128
    try:
        from html import escape
        if not os.path.exists(path): return ""
        start_line = (p - 1) * num
        count = start_line + num
        fp = open(path, 'rb')

        buf = ""
        fp.seek(-1, 2)
        if fp.read(1) == "\n": fp.seek(-1, 2)
        data = []
        total_len = 0
        b = True
        n = 0

        for i in range(count):
            while True:
                newline_pos = str.rfind(str(buf), "\n")

                pos = fp.tell()
                if newline_pos != -1:
                    if n >= start_line:
                        line = buf[newline_pos + 1:]
                        line_len = len(line)
                        total_len += line_len
                        sp_len = total_len - max_len
                        if sp_len > 0:
                            line = line[sp_len:]
                        try:
                            data.insert(0, escape(line))
                        except:
                            pass
                    buf = buf[:newline_pos]
                    n += 1
                    break
                else:
                    if pos == 0:
                        b = False
                        break
                    to_read = min(4096, pos)
                    fp.seek(-to_read, 1)
                    t_buf = fp.read(to_read)
                    if pyVersion == 3:
                        try:
                            if type(t_buf) == bytes: t_buf = t_buf.decode('utf-8')
                        except:
                            try:
                                if type(t_buf) == bytes: t_buf = t_buf.decode('gbk')
                            except:
                                t_buf = str(t_buf)
                    buf = t_buf + buf
                    fp.seek(-to_read, 1)
                    if pos - to_read == 0:
                        buf = "\n" + buf
                if total_len >= max_len: break
            if not b: break
        fp.close()
        result = "\n".join(data)

        if not result: raise Exception('null')
    except:
        result = ''  # ExecShell("tail -n {} {}".format(num,path))[0]
        if len(result) > max_len:
            result = result[-max_len:]

    try:
        try:
            result = json.dumps(result)
            return json.loads(result).strip()
        except:
            if pyVersion == 2:
                result = result.decode('utf8', errors='ignore')
            else:
                result = result.encode('utf-8', errors='ignore').decode("utf-8", errors="ignore")
        return result.strip()
    except:
        return ""



#根据路径获取文件
def get_path_size(path):

    if not os.path.exists(path): return 0;
    if not os.path.isdir(path): return os.path.getsize(path)
    size_total = 0
    for nf in os.walk(path):
        for f in nf[2]:
            filename = nf[0] + '/' + f
            if not os.path.exists(filename): continue;
            if os.path.islink(filename): continue;
            size_total += os.path.getsize(filename)
    return size_total


def get_dos_disk():
    data = {}
    import win32file
    diskIo = psutil.disk_partitions()
    for x in diskIo:
        path = x.mountpoint.replace("\\","/")
        d = path[:2]
        device = win32file.QueryDosDevice(d).replace('\x00\x00', '')
        data[device] = d

    return data

# 校验路径安全
def path_safe_check(path, force=True):
    if len(path) > 256: return False
    checks = ['..', './', '\\', '%', '$', '^', '&', '*', '~', '"', "'", ';', '|', '{', '}', '`']
    for c in checks:
        if path.find(c) != -1: return False
    if force:
        rep = r"^[\w\s\.\/-]+$"
        if not re.match(rep, path): return False
    return True

def downloadFile(url, filename):
    import requests
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    res = requests.get(url, headers=get_requests_headers(), timeout=120, stream=True, verify=False)

    with open(filename, "wb") as f:
        for _chunk in res.iter_content(chunk_size=8192):
            f.write(_chunk)
    return True

def downloadFileByWget(url, filename):
    import os, time
    loacl_path = '{}/script/wget.exe'.format(os.getenv('BT_PANEL'))
    if not os.path.exists(loacl_path): downloadFile(get_url() + '/win/panel/data/wget.exe', loacl_path)

    shell = "{} {} -O {} -t 5 -T 60  --no-check-certificate --auth-no-challenge --force-directorie ".format(loacl_path, url, filename)
    os.system(shell)

    num = 0
    re_size = 0
    while num <= 20:
        if os.path.exists(filename):
            cr_size = os.path.getsize(filename)
            if re_size > 0 and re_size == cr_size:
                break
            else:
                re_size = cr_size
        time.sleep(0.5)
        num += 1

    else:
        if os.path.exists(filename):
            if os.path.getsize(filename) < 1:os.remove(filename)   


def rmdir(sfile, mkdir=False):
    """
    @删除文件/目录
    """
    if not os.path.exists(sfile):
        if mkdir: os.makedirs(sfile)
        return False
    import shutil
    path = os.path.dirname(sfile)
    try:
        dfile = '{}/{}.del'.format(path, GetRandomString(12))
        try:
            if os.path.isfile(sfile):
                os.remove(sfile)
            else:
                shutil.rmtree(sfile, True)
        except : pass
        if os.path.exists(sfile): os.rename(sfile, dfile)
    except:
        pass

    for x in os.listdir(path):
        try:
            if x[-4:] == '.del':
                tpath = '{}/{}'.format(path, x)
                if os.path.isfile(tpath):
                    os.remove(tpath)
                else:
                    shutil.rmtree(tpath, True)
        except:
            pass

    if mkdir: os.makedirs(sfile)

def rmtree(sfile):
    """
    删除目录
    @sfile 目录路径
    """
    if not os.path.exists(sfile): return False
    import shutil
    try:
        shutil.rmtree(sfile, True)
        return True
    except:
        ExecShell("attrib -r {}".format(to_path(sfile)))
        shutil.rmtree(sfile, True)
        return True

def copytree(src, dst):
    """
    重新拷贝目录方法
    @src 源目录
    @dst 新目录
    """
    import shutil
    names = os.listdir(src)
    if not os.path.exists(dst):  os.makedirs(dst)
    for name in names:
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if os.path.isdir(srcname):
                copytree(srcname, dstname)
            else:
                shutil.copy2(srcname, dstname)
        except:
            pass

def move(sfile, dfile):
    """
    重写文件移动
    @sfile 源文件路径
    @dfile 新文件路径
    """
    dfile = dfile.replace('//', '/')
    sfile = sfile.replace('//', '/')
    import shutil
    if not os.path.exists(sfile): return False
    if dfile.rstrip('/') == sfile.rstrip('/'):  return False

    dfile.rstrip()
    if sfile.lower() == dfile.lower():
        os.rename(sfile, dfile);
        return True;

    is_dir = os.path.isdir(sfile)
    if not os.path.exists(dfile) or not is_dir:
        try:
            if os.path.exists(dfile): os.remove(dfile)
        except:
            ExecShell("attrib -r {}".format(to_path(dfile)))
            os.remove(dfile)

        shutil.move(sfile, dfile)
    else:
        copytree(sfile, dfile)
        if os.path.exists(sfile):
            if is_dir:
                shutil.rmtree(sfile, True)
            else:
                try:
                    os.remove(sfile)
                except:
                    ExecShell("attrib -r {}".format(to_path(dfile)))
                    os.remove(sfile)
    return True