import os
import sys
import re
#import getenc
#import chardet
from chardet.universaldetector import UniversalDetector

from tklib.tkobject import tkObject
from tklib.tkutils import is_file
import tklib.tkre as tkre

#=========================
# test parameters
path = 'test.ini'
#=========================


def get_encoding(path, defval = 'utf-8'):
    try:
        f = open(path, 'rb')
    except:
        return None

    detector = UniversalDetector()
    for line in f:
        detector.feed(line)
        if detector.done:
            break

    f.close()
    detector.close()

    encoding = detector.result['encoding']
    if encoding == 'SHIFT_JIS' or encoding == 'Windows-1254':
        return 'CP932'
    if encoding is None:
        return defval

    return encoding

def open_chardet(path = None, mode = None, encoding = None, def_encoding = None):
    if encoding is None:
       encoding = get_encoding(path)
#    print("44 encoding=", encoding)
    
    if encoding:
        return open(path, 'r', encoding = encoding)
    else:
        return open(path, 'r', encoding = 'shift_jis')

class tkFile(tkObject):
    def __init__(self, path = None, mode = 'r', encoding = 'utf-8', OpenFile = True, IsPrint = True, **args):
#        super().__init__(path, mode, **args)
        self.fp   = None
        self.path = None
        self.mode = 'r'
        self.encoding   = encoding
        self.charcode   = None
        self.path       = self.IfYes(path is not None, path, self.path)
        self.mode       = self.IfYes(mode is not None, mode, self.mode)
        self.last_match = None
        self.update(**args)

        if OpenFile and self.path is not None:
            self.open(self.path, self.mode, encoding = encoding, IsPrint = IsPrint)

    def __del__(self):
        self.close()
        super(tkFile, self).__del__()

    def __str__(self):
        return self.ClassPath()

    def SetPath(self, path = None, mode = None):
        self.path = self.IfYes(path is not None, path, self.path)
        self.mode = self.IfYes(mode is not None, mode, self.mode)

    def open(self, path = None, mode = None, IsPrint = True, encoding = None):
        if path is None:
            path = self.path
        if path is None:
            if IsPrint:
                print("")
                print(f"Error in tkfile.open(): path is not given")
            return None

        if mode is None:
            mode = 'r'

        self.SetPath(path, mode)
        if self.fp:
            self.close()

        self.fp = None
#        if not is_file(path):
#            return None

        if 'r' in mode and not os.path.isfile(path):
            if IsPrint:
                print("")
                print(f"Error in tkfile.open(): [{path}] does not exist")
            return None

        if encoding is None:
            encoding = self.get('encoding', None)
        if encoding is not None and type(encoding) is not str:
            encoding = None

        if is_file(path) and encoding is None:
            with open(path, 'rb') as f:
                detector = UniversalDetector()
                for line in f:
                    detector.feed(line)
                    if detector.done:
                        break
                detector.close()
                result = detector.result
#                print("result=", result['encoding'])
                if result['encoding'] == 'SHIFT_JIS':
                    encoding = 'CP932'
                elif result['encoding'] == 'MacRoman':
                    encoding = 'CP932'

        if encoding is None:
            encoding = 'utf-8'
#            self.charcode = getenc.getEncode(path)
            self.charcode = 'utf-8'

#        self.fp = open(path, self.mode, encoding = encoding)
        try:
            self.fp = open(path, self.mode, encoding = encoding)
        except:
            if not IsPrint:
                return None

            if self.mode == 'r':
#                self.errormsg(sys._getframe().f_code.co_name, 
                self.errormsg("tkfile.open()", 
                    "Can not read [{}]".format(self.path))
            elif self.mode == 'w':
#                self.errormsg(sys._getframe().f_code.co_name, 
                self.errormsg("tkfile.open()", 
                    "Can not write to [{}]".format(self.path))
            else:
#                self.errormsg(sys._getframe().f_code.co_name, 
                self.errormsg("tkfile.open()", 
                    "Can not open [{}]".format(self.path))
            return None

        return self.fp

    def Open(self, path = None, mode = None, IsPrint = True, encoding = None):
        return self.open(path, mode, IsPrint, encoding = encoding)

    def close(self):
        if self.fp is not None:
            self.fp.close()
            self.fp = None

    def Close(self):
        self.close()

    def read(self):
        return self.fp.read()

    def Read(self):
        return self.read()

    def readline(self):
        if self.fp is None: return None
        try:
            return self.fp.readline()
        except Exception as e:
            print(f"Error in tkfile.readline(): {e}")
            return ''

    def ReadLine(self):
        return self.readline()

    def ReadLineList(self):
        if self.fp is None: return None
        self.lines = self.fp.readlines()
        return self.lines

    def ReadCharList(self):
        if self.fp is None: return None
        s = self.Read()
        return list(s)

    def ReadLines(self):
        if self.fp is None: return None
        return ''.join(self.fp.readlines())

    def write(self, s):
        if self.fp is None:
            return False
        self.fp.write(s)
        return True

    def Write(self, s):
        return self.write(s)

    def write_lines(self, lines):
        if self.fp is None:
            return False

        for l in lines:
            ret = self.fp.write(l)
            if not ret:
                return ret

        return True

    def WriteLines(self, lines):
        return self.write_lines(lines)

    def CopyUntil(self, out, reg = None):
#        print("reg=", reg)
        if reg is None:
            line = self.ReadLine()
            while line:
                print("l=", line)
                out.Write(line)
                line = self.ReadLine()
                return None

        line = self.ReadLine()
        while line:
#            print("line [{}]".format(line), "  reg=[{}]".format(reg))
            if line is None:
                break
            match = re.search(reg, line)
            if match:
                print("hit")
                return match
            out.Write(line)
            line = self.ReadLine()
        return None

# eof can be checked by:  line = fp.readline(); if not line
# or if len(fp.read(1)) == 0 
    def eof(self):
        if self.fp is None:
            return True
        if self.fp.tell() == os.fstat(self.fp.fileno()).st_size:
            return True
        return False

    def rewind(self):
        if self.fp is None:
            return
        self.fp.seek(0)

    def Rewind(self):
        self.rewind()

    # os.SEEK_SET os.SEEK_CUR  os.SEEK_END
    def seek(self, offset, whence = os.SEEK_SET):
        if self.fp is None:
            return
        self.fp.seek(offset, whence)

    def Seek(self, offset, whence = os.SEEK_SET):
        self.seek(offset, whence = whence)

    def tell(self):
        if self.fp is None:
            return 0
        return self.fp.tell()

    def Tell(self):
        return self.tell()
        
    def skip_to(self, pattern, origin = None, re_flag = None, max_lines = -1):
        if re_flag is None:
            re_flag = re.IGNORECASE
#        print("pattern=[{}]".format(pattern))

        if origin is not None:
            self.fp.seek(origin)

        nlines = 0
        line = ''
        while 1:
            if max_lines > 0 and nlines > max_lines: break
            nlines += 1

            line = self.ReadLine()
            if not line: break

#            print("  line = ", line.strip())
            m = re.search(pattern, line, re_flag)
            if m:
                self.last_match = m
                line = self.DelCRLF(line)
                return line
            continue

        return None

    def SkipTo(self, pattern, origin = None, re_flag = None, max_lines = -1):
        return self.skip_to(pattern, origin = origin, re_flag = re_flag, max_lines = max_lines)

    def search_to(self, pattern, origin = None, defval = None, max_lines = -1):
        re_flag = 'i'
#        re_flag = re.IGNORECASE
#        print("pattern=[{}]".format(pattern))

        if pattern is None:
            return defval

        if origin is not None:
            self.fp.seek(origin)

        nlines = 0
        line = ''
        while 1:
            if max_lines > 0 and nlines > max_lines: break
            nlines += 1

            line = self.ReadLine()
            if not line: break

#            print("  line = ", line)
#            m = re.search(pattern, line, re_flag)
#            print("[{}] in [{}]".format("[Boot]", line), "  m=", m)
            m = tkre.Search(pattern, line, re_flag)
            if m:
                return m
            continue

        if defval is not None:
            return [line, defval]

        return None

    def SearchTo(self, pattern, origin = None, defval = None, max_lines = -1):
        return self.search_to(pattern, origin = origin, defval = origin, max_lines = max_lines)

    def Match(self, reg, str, flag = '', defval = None):
        if str is None:
            return defval

        return tkre.Match(reg, str, flag)

    def Search(self, reg, str, flag = '', defval = None):
        if str is None:
            return defval

        return tkre.Search(reg, str, flag)

    def ReadBlock(self, end_regexp = r'^\s*$'):
        lines = []
        while 1:
            pos = self.fp.tell()
            line = self.fp.eadline()
            if not line or re.search(end_regexp, line):
                self.fp.seek(pos)
                return lines

            lines.append(line)

    def Split(self, reg, str):
        return tkre.Split(reg, str)

    def shSplit(self, reg, str):
        return tkre.shSplit(reg, str)

    def Sub(self, reg, target, str, n = 0):
        return tkre.Sub(reg, target, str, n)

    def SubN(self, reg, target, str, n = 0):
        return tkre.SubN(reg, target, str, n)

    def DelCRLF(self, str):
        return re.sub(r"[\n\r]+$", '', str)

    def DelSpace(self, str):
        return str.strip()

    def DelTopSpace(self, str):
        return str.lstrip()

    def DelLastSpace(self, str):
        return str.rstrip()


def main(path):
    fp = tkFile(path)
    print("fp=", type(fp.fp))
#    vars = ini.readall()

    fp.Rewind()
    s = fp.ReadLine()
    print("ReadLine=", s)

    fp.Rewind()
    ss = fp.ReadLines()
    print("ReadLines=\n", ss)

    fp.Rewind()
    cs = fp.ReadCharList()
    print("Chars=\n", cs)
    fp.Close()

if __name__ == "__main__":
    main(path)


