#-*- coding: utf-8 -*-

# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import time, os, sys
import subprocess
import fcntl
from OpenSSL import crypto
import shlex
import sudsds
from calculate.core.server.cert_cmd import getHwAddr, getIpLocal

# get list of certificate and session id
import termios


def get_sid (SID_FILE):
    if not os.path.exists(SID_FILE):
        fi = open(SID_FILE, 'w')
        fi.write('0')
        fi.close()
        sid = 0
    else:
        fi = open(SID_FILE, 'r')
        sid = fi.read()
        fi.close()
    return sid

def clear ():
    """ delete caching suds file """
    try:
        import glob
        for filename in glob.glob("/tmp/suds/suds-*"):
            #print "delete", filename
            os.unlink (filename)
    except:
        print _("Failed to clear the cache! ")
        return 1

def clear ():
    """ delete caching suds file """
    try:
        import glob
        for filename in glob.glob("/tmp/suds/suds-*"):
            #print "delete", filename
            try:
                os.unlink (filename)
            except OSError as e:
                _print(e.message)
    except:
        print _("Failed to clear the cache! ")
        return 1

def get_ip_global():
    import urllib2

    strURL = 'http://api.wipmania.com/'
    f = urllib2.urlopen(urllib2.Request(strURL))
    response = f.read()
    outerIP = response.split("<br>")[0]
    f.close()
    return outerIP

def myGetch():
    """ get one character without pressing Enter """
    fd = sys.stdin.fileno()

    oldterm = termios.tcgetattr(fd)
    newattr = termios.tcgetattr(fd)
    newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
    termios.tcsetattr(fd, termios.TCSANOW, newattr)

    oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

    try:        
        while 1:            
            try:
                c = sys.stdin.read(1)
                break
            except IOError: pass
    finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
        fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
        return c

def get_ip_mac_type(client_type = None):
    results = []
    #try:
    results.append ( getIpLocal() )
    #except:
        #results.append ('no_ip')
    #try:
    results.append ( getHwAddr())
    #except:
        #results.append ('no_mac')
    if client_type:
        results.append (client_type)
    else:
        results.append ('console')
    return results
    
def client_install(client):
    sid = get_sid(client.SID_FILE)
    list_pid = client.service.install_system_view(sid)

def create_obj(client, method_name):
    """ create object indispensable for transfer to the server function """
    sd_item = 0
    num_port = 0
    operation_from_port = 0
    inf_param = 1
    param_type = 0
    ns_name = 0
    ns_type = 1
    param = 1
    pref = ""

    sd = client.sd[sd_item]

    # get parameter type
    operation = sd.ports[num_port][operation_from_port]
    
    info = operation.methods.get(method_name)
    if not info:
        raise sudsds.MethodNotFound(method_name)
    type_op = info.binding.input.param_defs(info)[param][inf_param]
    str_type = type_op.type[param_type]
    
    # get prefix
    str_ns = type_op.type[ns_type]
    ##client.wsdl.schema.root.normalizePrefixes()
    nsprefix = sd.prefixes
    
    # Find a match prefix
    for pref_num in range (0, len(nsprefix)):
        if str_ns == sd.prefixes[pref_num][ns_type]:
            pref = sd.prefixes[pref_num][ns_name]
    # Combine in a type
    if not pref:
        pref = sd.getprefix(str_ns)
    for_factory = pref + _(":") + str_type

    NewType = client.factory.create(for_factory)
    return NewType
    
def listToArray (client, _list, _type = 'string'):
    Array = client.factory.create('%sArray' %_type)
    for i in _list:
        Array['%s' %_type].append(i)
    return Array
    
def listToArrayArray (client, _list, _type = 'string'):
    ArrayArray = client.factory.create('%sArrayArray' %_type)
    for i in _list:
        Array = client.factory.create('%sArray' %_type)
        for j in i:
            Array[_type].append(j)
        ArrayArray['%sArray' %_type].append(Array)
    return ArrayArray

class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration
    
    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

#################API FUNCTION###############################
def show_view(view):
    print "+====== show view! ======+"
def show_table(table, item):
    print "+==============  %-13s===========+" %item.message
    
    sys.stdout.flush()
    
    sys.stdout.write ("=========")
    for i in range (1, len(table.head[0])):
        sys.stdout.write ("===========")
    print
    # print head table
    for head in table.head[0]:
        sys.stdout.write(" %-6s |  " %head)
    sys.stdout.write("\n")
    
    sys.stdout.write ("+=======+")
    for i in range (1, len(table.head[0])):
        sys.stdout.write ("==========+")
    print
    
    # print body table
    for line in table.body[0]:
        for i in line[0]:
            sys.stdout.write("%6s  |  " %i)
        sys.stdout.write("\n")
    
    sys.stdout.write ("+=======+")
    for i in range (1, len(table.head[0])):
        sys.stdout.write ("==========+")
    print
    
    
#HEADER = '\033[95m'
    #OKBLUE = '\033[94m'
    #OKGREEN = '\033[92m'
    #ENDC = '\033[0m'
def show_error(item):
    FAIL = '\033[31m'
    ENDC = '\033[0m'
    print FAIL + "ERROR"
    print FAIL + item.message
    print ENDC
    
def show_warning(item):
    WARNING = '\033[91m'
    print WARNING + "Warning"
    print WARNING + item.message
    ENDC = '\033[0m'
    print ENDC
    
def show_group(item):
    print "Group"
    print item.message

def show_result(result):
    print "Result = ", result.message

def startTask(item):
    print "start Task"
    print item.message

def endTask(item):
    print item.message
    print "end Task\n\n"
    
def beginFrame(item):
    pass

def endFrame(item):
    pass

def startGroup(item):
    pass

def endGruop(item):
    pass

def callView(item, sid):
    print "\n\n",item.message
    try:
        view = client.service[0][item.message] (sid)
        show_view (view)
    except:
        print _("Error")

#################MESSAGE####################################

def analysis(client, sid, s):
    """ analysis of the bounced message method """
    messages = s[0]
    for mess in messages:
        if mess.type == 'pid':
            get_messages(client, sid, mess.message)
        if mess.type == 'error':
            show_error(mess)
        if mess.type == 'warning':
            show_warning(mess)

def get_message(client, item, sid, pid):
    """ get one message by its type """
    for case in switch(item.type):
        if case('normal') or case('plain'):
            sys.stdout.flush()
            sys.stdout.write('\x1b[1;33m' + item.message + '\033[0m')
            #print item.message
            return 1
        if case('progress'):
            get_Progress(client, sid, pid, item.id)
            return 1
        if case('error'):
            show_error(item)
            if item.message == "403 Forbidden":
                return 0
            return 1
        if case('warning'):
            show_warning(item)
            return 1
        if case('table'):
            get_Table(client, sid, pid, item)
            return 1
        if case('group'):
            show_group(client, sid, pid, item)
            return 1
        if case('question'):
            send_Message(client, sid, pid, item)
            return 1
        if case('password'):
            send_Password(client, sid, pid, item)
            return 1
        if case('startTask'):
            startTask(item)
            return 1
        if case('endTask'):
            endTask(item)
            return 1
        if case('beginFrame'):
            beginFrame(item)
            return 1
        if case('endFrame'):
            endFrame(item)
            return 0
        if case('startGroup'):
            startGroup(item)
            return 1
        if case('endGruop'):
            endGruop(item)
            return 1
        if case('briefParams'):
            callView(item, sid)
        if case(): # default, could also just omit condition or 'if True'
            return 1

def get_messages(client, sid, pid):
    """ get frame in a separate thread """
    #thread_messages = threading.Thread(target=get_Frame,\
                                       #args = (client, sid, pid))
    #thread_messages.start()
    get_Frame(client, sid, pid)


def get_Frame(client, sid, pid):
    """ get all messages, until type is not endFrame (or Error) """
    end_frame = 1
    while end_frame:
        current_frame = client.service.get_frame(sid, pid)
        while current_frame in [None, [], ""]:
            time.sleep(float(client.frame_period))
            current_frame = client.service.get_frame(sid, pid)
        for item in current_frame[0]:
            end_frame = get_message(client, item, sid, pid)
            
def get_entire_frame(client):
    """ get entire frame, from beginning (if client disconnected) """
    sid = get_sid(client.SID_FILE)
    list_pid = client.service.list_pid(sid = sid)
    
    if list_pid[0] == [0]:
        return 0
    for pid in list_pid[0]:
        end_frame = 1
        while end_frame:
            current_frame = client.service.get_entire_frame(sid, pid)
            while current_frame in [None, [], ""]:
                time.sleep(1)
                current_frame = client.service.get_frame(sid, pid)
            for item in current_frame[0]:
                end_frame = get_message(client, item, sid, pid)

def get_Progress(client, sid, pid, id):
    """ get progress for the current job """
    percent = client.service.get_progress(sid, pid, id)
    temp_progress = -1
    while percent < 100 and percent >= 0 :
        if temp_progress != percent:
            print _("Percentage = %s") %percent
            temp_progress = percent
        time.sleep(1)
        percent = client.service.get_progress(sid, pid, id)
    if percent < 0:
        print _("Task error by %d") %(0 - percent) + "%"
    else:
        print _("Percentage = %s") %percent

def get_Table(client, sid, pid, item):
    table = client.service.get_table(sid, pid, item.id)
    show_table(table, item)

def send_Message(client, sid, pid, item):
    """ send answer to the question """
    answer = raw_input (item.message)
    result = client.service.send_message(sid, pid, answer)
    show_result(result)
    
def send_Password(client, sid, pid, item):
    """ send password """
    from getpass import getpass
    password = getpass(prompt=item.message)
    result = client.service.send_message(sid, pid, password)
    show_result(result)
    

def _return_revoked_serials(self, crlfile):
    try:
        serials = []
        crltext = open(crlfile, 'r').read()
        crl = crypto.load_crl(crypto.FILETYPE_PEM, crltext)
        revs = crl.get_revoked()
        for revoked in revs:
            serials.append(str(revoked.get_serial()))
        return serials
    except (ImportError, AttributeError), e:
        call = '/usr/bin/openssl crl -text -noout -in %s' % crlfile
        call = shlex.split(call)
        serials = []
        (res,err) = subprocess.Popen(call, stdout=subprocess.PIPE).communicate()
        for line in res.split('\n'):
            if line.find('Serial Number:') == -1:
                continue
            (crap, serial) = line.split(':')
            serial = serial.strip()
            serial = int(serial, 16)
            serials.append(serial)
        return serials
