#/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This file is part of Karesansui.
#
# Copyright (C) 2009 HDE, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#

import os
import sys
import stat
import subprocess
import time
import datetime
import re
import pwd
import grp
import fcntl
import random

from installer.const import *

global logfile
env = os._Environ(os.environ)
logfile = env.get("LOGFILE")

def generate_uuid():
    """
    <comment-ja>
    ランダムなUUIDを生成する

    @return: UUID用の16個のバイト要素を持つ配列
    </comment-ja>
    <comment-en>
    Generate UUID

    @return: Array UUID
    </comment-en>
    """
    uuid = []
    for _x in range(0, 16):
      uuid.append(random.randint(0x00,0xff))
    return uuid

def string_from_uuid(uuid):
    """
    <comment-ja>
    UUIDデータを文字列に変換する

    @param uuid: generate_uuid関数等で生成されたUUIDデータ
    @return: UUID文字列
    </comment-ja>
    <comment-en>
    Convert UUID data to string

    @param uuid: UUID data that was generated by certain function like as generate_uuid()
    @return: The string that stands for uuid
    </comment-en>
    """
    tuuid = tuple(uuid)
    return "-".join(["%02x"*4 % tuuid[0:4],
                    "%02x"*2 % tuuid[4:6],
                    "%02x"*2 % tuuid[6:8],
                    "%02x"*2 % tuuid[8:10],
                    "%02x"*6 % tuuid[10:16]
                   ]);

def detect_encoding(string,encoding_list=None):
    func = lambda data,encoding: data.decode(encoding) and encoding

    if not encoding_list:
        encoding_list = [ 'euc-jp', 'utf-8', 'shift-jis', 'iso2022-jp' ]

    for encoding in encoding_list:
        try:
            return func(string, encoding)
        except:
            pass

    return None

def execute_command(command_args):
    global logfile
    ret = -1
    res = []

    subproc_args = { 'stdin': subprocess.PIPE,
                     'stdout': subprocess.PIPE,
                     'stderr': subprocess.STDOUT,
#                     'shell': True,
                     'cwd': os.getcwd(),
                     'close_fds': True,
                   }

    if logfile is None:
        logfile = "/dev/null"
    logf = open(logfile, "a")

    try:
        pp = subprocess.Popen(command_args, **subproc_args)
        logf.write("Exec: '%s'\n" % (command_args))
    except OSError:
        logf.write("Exec: '%s' failed.\n" % (command_args))
        logf.close()
        return [ret,res]

    (stdouterr, stdin) = (pp.stdout, pp.stdin)
    while True:
        line = stdouterr.readline()
        logf.write(line)
        if not line:
            break
        line = line.rstrip()
        res.append(unicode(line, detect_encoding(line)).encode("utf-8"))
    ret = pp.wait()

    logf.close()
    return [ret,res]

def is_int(val):
    try:
        ret = int(val)
        return True
    except (TypeError, ValueError):
        return False

def r_chown(path,owner):
    global logfile
    owner = str(owner)
    if not os.path.exists(path):
        return False

    if ':' in owner:
        user, group = owner.split(':')
    else:
        user, group = [owner,None ]

    if is_int(user) is not True:
        try:
            pw = pwd.getpwnam(user)
        except:
            return False
    else:
        try:
            pw = pwd.getpwuid(int(user))
        except:
            return False
    uid = pw[2]

    if group == None:
        statinfo = os.stat(path)
        gid = statinfo.st_gid
    else:
        if is_int(group) is not True:
            try:
                gr = grp.getgrnam(group)
            except:
                return False
        else:
            try:
                gr = grp.getgrgid(int(group))
            except:
                return False
        gid = gr[2]

    if os.path.isfile(path) or os.path.islink(path):
        try:
            os.chown(path,uid,gid)
        except:
            return False

    elif os.path.isdir(path):
        try:
            os.chown(path,uid,gid)
        except:
            return False

        for name in os.listdir(path):
            sub_path = os.path.join(path, name)
            r_chown(sub_path,owner)

    return True

def r_chgrp(path,group):
    global logfile
    group = str(group)
    if not os.path.exists(path):
        return False

    statinfo = os.stat(path)
    uid = statinfo.st_uid

    if is_int(group) is not True:
        try:
            gr = grp.getgrnam(group)
        except:
            return False
    else:
        try:
            gr = grp.getgrgid(int(group))
        except:
            return False
    gid = gr[2]

    if os.path.isfile(path) or os.path.islink(path):
        try:
            os.chown(path,uid,gid)
        except:
            return False

    elif os.path.isdir(path):
        try:
            os.chown(path,uid,gid)
        except:
            return False

        for name in os.listdir(path):
            sub_path = os.path.join(path, name)
            r_chgrp(sub_path,group)

    return True

def r_chmod(path,perm):
    perm_regex = re.compile(r"""^(?P<user>[ugo]{0,3})(?P<action>[\+\-])(?P<value>[rwxst]{1,3})$""")

    user_table = {"u":"USR","g":"GRP","o":"OTH"}
    perm_table = {"r":"R","w":"W","x":"X"}

    if not os.path.exists(path):
        return False

    original_perm = perm
    if is_int(perm):
        if type(perm) == str:
            perm = oct2dec(perm)
        new_perm = perm
    else:
        s = os.lstat(path)
        new_perm = stat.S_IMODE(s.st_mode)

        m = perm_regex.match(perm)
        if m:
            user = m.group('user')
            action = m.group('action')
            value = m.group('value')
            if user == "":
                user = "ugo"

            mask_perm = 0
            for k,v in user_table.iteritems():
                if k in user:
                    for k2,v2 in perm_table.iteritems():
                        if k2 in value:
                            exec("bit = stat.S_I%s%s" % (v2,v,))
                            mask_perm = mask_perm | bit


            if "t" in value:
                bit = stat.S_ISVTX
                mask_perm = mask_perm | bit

            if "s" in value:
                if "u" in user:
                    bit = stat.S_ISUID
                    mask_perm = mask_perm | bit
                if "g" in user:
                    bit = stat.S_ISGID
                    mask_perm = mask_perm | bit

            #print "new_perm1:" + dec2oct(new_perm)
            #print "mask_perm:" + dec2oct(mask_perm)
            if action == "-":
                new_perm = new_perm & (~ mask_perm)
            elif action == "+":
                new_perm = new_perm | mask_perm
            #print "new_perm2:" + dec2oct(new_perm)

        else:
            return False

    if os.path.isfile(path) or os.path.islink(path):
        try:
            os.chmod(path,new_perm)
        except:
            return False

    elif os.path.isdir(path):
        try:
            os.chmod(path,new_perm)
        except:
            return False

        for name in os.listdir(path):
            sub_path = os.path.join(path, name)
            r_chmod(sub_path,original_perm)

    return True

def sh_config_read(filename):
    ret = {}
    try:
        fp = open(filename,"r")
        fcntl.lockf(fp.fileno(), fcntl.LOCK_SH)
        for line in fp.readlines():
            line = line.strip()
            if len(line) <= 0 or line[0] == "#":
                continue
            key, value = line.split('=',1)
            ret[key] = value
        fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
        fp.close()
    except:
        ret = False

    return ret

def sh_config_write(filename,opts):
    ret = True

    res = {}
    if type(opts) == dict:
        res = opts
    else:
        for k in dir(opts):
            res[k] = getattr(opts,k)

    try:
        fp = open(filename,"w")
        fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
        for k,v in res.iteritems():
            if type(v) == str and k[0:2] != "__" and k[0:4] != "pass":
                fp.write("%s=%s\n" % (k, v,))
        fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
        fp.close()
    except:
        ret = False

    return ret

def run_chkconfig(name,flag=None):
    ret = False

    if flag is None:
        (ret,res) = execute_command([COMMAND_CHKCONFIG,name])
    else:
        (ret,res) = execute_command([COMMAND_CHKCONFIG,name,flag])
    if ret == 0:
        ret = True

    return ret

def run_service(name,flag=None):
    ret = False

    if flag is None:
        (ret,res) = execute_command([COMMAND_SERVICE,name,"status"])
    else:
        (ret,res) = execute_command([COMMAND_SERVICE,name,flag])
    if ret == 0:
        ret = True

    return ret

def get_kss_url():
    import socket

    fqdn = socket.gethostname()
    urls = []

    url_prefix = sh_config_read(DEFAULT_KARESANSUI_CONF)["application.url.prefix"]

    """ HTTPS """
    ssl_port_regex = re.compile(r"^\$SERVER\[\"socket\"\] == \".*:(?P<port>[0-9]+)\"")
    try:
        fp = open(LIGHTY_SSL_CONF,"r")
        fcntl.lockf(fp.fileno(), fcntl.LOCK_SH)
        for line in fp.readlines():
            line = line.strip()
            m = ssl_port_regex.match(line)
            if m:
                ssl_port = m.group('port')
                if ssl_port == "443":
                    urls.append("https://%s%s/" % (fqdn,url_prefix))
                else:
                    urls.append("https://%s:%s%s/" % (fqdn,m.group('port'),url_prefix))
        fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
        fp.close()
    except:
        pass

    """ HTTP """
    try:
        port = sh_config_read(LIGHTY_PORT_CONF)["server.port"]
    except:
        port = "80"

    if port == "80":
        urls.append("http://%s%s/" % (fqdn,url_prefix))
    else:
        urls.append("http://%s:%s%s/" % (fqdn,port,url_prefix))

    return urls

def deco_msg(string,font="green"):
    if font == "bold":
        return "[1m%s[0m" % string
    elif font == "underline":
        return "[4m%s[0m" % string
    elif font == "red":
        return "[31m%s[0m" % string
    elif font == "green":
        return "[32m%s[0m" % string
    elif font == "orange":
        return "[33m%s[0m" % string
    elif font == "blue":
        return "[34m%s[0m" % string
    elif font == "gray":
        return "[37m%s[0m" % string
    elif font == "red|bold":
        return "[1m[31m%s[0m" % string
    elif font == "green|bold":
        return "[1m[32m%s[0m" % string
    elif font == "blue|bold":
        return "[1m[34m%s[0m" % string
    else:
        return string

def is_installed(name,rpmlib=None):
    if rpmlib is None:
        from installer.rpmlib import RpmLib
        rpmlib = RpmLib()
    try:
        rpmlib.doQuery("^%s$" % name)[name]
        ret = True
    except:
        ret = False
    rpmlib.__del__
    return ret

def is_updatable(fullpath, rpmlib=None):
    if rpmlib is None:
        from installer.rpmlib import RpmLib
        rpmlib = RpmLib()

    if os.path.isfile(fullpath) is False:
        return False
    try:
        try:
            ret = rpmlib.compareVersion(fullpath)
            if ret < 0:
                return True
            else:
                return False
        except:
            return False
    finally:
        rpmlib.__del__

def get_distrubution(rpmlib=None):
    ret = ('unknown',None)

    if rpmlib is None:
        from installer.rpmlib import RpmLib
        rpmlib = RpmLib()

    distros = [
      "centos-release",
      "redhat-release",
      "redhat-release-as",
      "redhat-release-es",
      "redhat-release-ws",
      "distribution-release",
      "miraclelinux-release",
      "fedora-release",
      "suse-release",
      "asianux-release",
    ]

    rpminfo = rpmlib.doQuery("")
    for _name in distros:
        try:
            _info = rpminfo[_name]
            ret = (_name, "%s-%s" % (_info["version"],_info["release"],))
            break
        except:
            pass
    rpmlib.__del__
    return ret
