# coding=utf-8
import os
import commands


class NginxConfig:
    def __init__(self, offset_char=' '):
        self.i = 0 #char iterator for parsing
        self.length = 0
        self.config = ''
        self.data = []
        self.off_char = offset_char

    def __getitem__(self, index):
        return self.data[index]

    def __setitem__(self, index, value):
        self.data[index] = value

    def __delitem__(self, index):
        del self.data[index]

    def __call__(self):
        return self.gen_config()

    def get_value(self, data):
        if isinstance(data, tuple):
            return data[1]
        elif isinstance(data, dict):
            return data['value']
        else:
            return data

    def get_name(self, data):
        if isinstance(data, tuple):
            return data[0]
        elif isinstance(data, dict):
            return data['name']
        else:
            return data

    def set(self, item_arr, value=None, param=None, name=None):
        if isinstance(item_arr, str):
            elem = item_arr
            parent = self.data
        elif isinstance(item_arr, list) and len(item_arr) == 1:
            elem = item_arr[0]
            parent = self.data
        else:
            elem = item_arr.pop()
            parent = self.get_value(self.get(item_arr))

        if parent is None:
            raise KeyError('No such block.')

        if isinstance(elem, str) and isinstance(value, str):
            #modifying text parameter
            for i, param in enumerate(parent):
                if isinstance(param, tuple):
                    if param[0] == elem:
                        if value is not None and name is not None:
                            parent[i] = (name, value)
                            return
                        elif value is not None:
                            parent[i] = (param[0], value)
                            return
                        elif name is not None:
                            parent[i] = (name, param[1])
                            return
                        raise TypeError('Not expected value type')

        elif isinstance(elem, tuple):
            #modifying block
            if len(elem) == 1:
                elem = (elem[0], '')
            for i, block in enumerate(parent):
                if isinstance(block, dict):
                    if elem == (block['name'], block['param']):
                        if value is not None and isinstance(value, list):
                            parent[i]['value'] = value
                            return
                        if param is not None and isinstance(param, str):
                            parent[i]['param'] = param
                            return
                        if name is not None and isinstance(name, str):
                            parent[i]['name'] = name
                            return
                        raise TypeError('Not expected value type')
        raise KeyError('No such parameter.')

    def get(self, item_arr, data=[]):
        if data == []:
            data = self.data
        if type(item_arr) in [str, tuple]:
            item = item_arr
        elif isinstance(item_arr, list):
            if len(item_arr) == 1:
                item = item_arr[0]
            else:
                element = item_arr.pop(0)
                if isinstance(element, tuple):#cannot be a string
                    if len(element) == 1:
                        element = (element[0], '')
                    for i, data_elem in enumerate(data):
                        if isinstance(data_elem, dict):
                            if (data_elem['name'], data_elem['param']) == element:
                                return self.get(item_arr, self.get_value(data[i]))

        if not 'item' in locals():
            raise KeyError('Error while getting parameter.')
        if isinstance(item, str):
            for i, elem in enumerate(data):
                if isinstance(elem, tuple):
                    if elem[0] == item:
                        return data[i]
        elif isinstance(item, tuple):
            if len(item) == 1:
                item = (item[0], '')
            for i, elem in enumerate(data):
                if isinstance(elem, dict):
                    if (elem['name'], elem['param']) == item:
                        return data[i]
        return None

    def append(self, item, root=[], position=None):
        if root == []:
            root = self.data
        elif root is None:
            raise AttributeError('Root element is None')
        if position:
            root.insert(position, item)
        else:
            root.append(item)

    def remove(self, item_arr, data=[]):
        if data == []:
            data = self.data
        if type(item_arr) in [str, tuple]:
            item = item_arr
        elif isinstance(item_arr, list):
            if len(item_arr) == 1:
                item = item_arr[0]
            else:
                elem = item_arr.pop(0)
                if type(elem) in [tuple,str]:
                    self.remove(item_arr, self.get_value(self.get(elem, data)))
                    return

        if isinstance(item, str):
            for i,elem in enumerate(data):
                if isinstance(elem, tuple):
                    if elem[0] == item:
                        del data[i]
                        return
        elif isinstance(item, tuple):
            if len(item) == 1:
                item = (item[0], '')
            for i,elem in enumerate(data):
                if isinstance(elem, dict):
                    if (elem['name'], elem['param']) == item:
                        del data[i]
                        return
        else:
            raise AttributeError("Unknown item type '%s' in item_arr" % item.__class__.__name__)
        raise KeyError('Unable to remove')

    def load(self, config):
        self.config = config
        self.length = len(config) - 1
        self.i = 0
        self.data = self.parse_block()

    def loadf(self, filename):
        with open(filename, 'r') as f:
            conf = f.read()
            self.load(conf)

    def savef(self, filename):
        with open(filename, 'w') as f:
            conf = self.gen_config()
            f.write(conf)

    def parse_block(self):
        data = []
        param_name = None
        param_value = None
        buf = ''
        while self.i < self.length:
            if self.config[self.i] == '\n': #multiline value
                if buf and param_name:
                    if param_value is None:
                        param_value = []
                    param_value.append(buf.strip())
                    buf = ''
            elif self.config[self.i] == ' ':
                if not param_name and len(buf.strip()) > 0:
                    param_name = buf.strip()
                    buf = ''
                else:
                    buf += self.config[self.i]
            elif self.config[self.i] == ';':
                if isinstance(param_value, list):
                    param_value.append(buf.strip())
                else:
                    param_value = buf.strip()
                if param_name:
                    data.append((param_name, param_value))
                else:
                    data.append((param_value,))
                param_name = None
                param_value = None
                buf = ''
            elif self.config[self.i] == '{':
                self.i += 1
                block = self.parse_block()
                data.append({'name':param_name, 'param':buf.strip(), 'value':block})
                param_name = None
                param_value = None
                buf = ''
            elif self.config[self.i] == '}':
                self.i += 1
                return data
            elif self.config[self.i] == '#': #skip comments
                while self.i < self.length and self.config[self.i] != '\n':
                    self.i += 1
            else:
                buf += self.config[self.i]
            self.i += 1
        return data

    def gen_block(self, blocks, offset):
        subrez = '' # ready to return string
        block_name = None
        block_param = ''
        for i, block in enumerate(blocks):
            if isinstance(block, tuple):
                if len(block) == 1 and type(block[0]) == str: #single param
                    subrez += self.off_char * offset + '%s;\n' % (block[0])
                elif isinstance(block[1], str):
                    subrez += self.off_char * offset + '%s %s;\n' % (block[0], block[1])
                else: #multiline
                    subrez += self.off_char * offset + '%s %s;\n' % (block[0],
                        self.gen_block(block[1], offset + len(block[0]) + 1))

            elif isinstance(block, dict):
                block_value = self.gen_block(block['value'], offset + 4)
                if block['param']:
                    param = block['param'] + ' '
                else:
                    param = ''
                if subrez != '':
                    subrez += '\n'
                subrez += '%(offset)s%(name)s %(param)s{\n%(data)s%(offset)s}\n' % {
                    'offset':self.off_char * offset, 'name':block['name'], 'data':block_value,
                    'param':param}

            elif isinstance(block, str): #multiline params
                if i == 0:
                    subrez += '%s\n' % block
                else:
                    subrez += '%s%s\n' % (self.off_char * offset, block)

        if block_name:
            return '%(offset)s%(name)s %(param)s{\n%(data)s%(offset)s}\n' % {
                'offset':self.off_char * offset, 'name':block_name, 'data':subrez,
                'param':block_param}
        else:
            return subrez

    def gen_config(self, offset_char=' '):
        self.off_char = offset_char
        return self.gen_block(self.data, 0)


class NginxConf(NginxConfig):
    read_conf = ""

    def __init__(self, offset_char=' '):
        NginxConfig.__init__(self, offset_char=' ')
        self.nginx_path()

    def nginx_path(self):
        nginxpidcmd = "ps aux|grep -v grep|grep nginx|grep master|awk '{print $2}'"
        st, nginx_pid = commands.getstatusoutput(nginxpidcmd)
        if st == 0 and nginx_pid:
            nginx_cmd = "sudo ls -l /proc/%s|grep ^l|grep exe|awk '{print $NF}'" % nginx_pid
            stat, nginx_path = commands.getstatusoutput(nginx_cmd)
            if stat == 0 and nginx_path:
                nginx_sbin_dir = os.path.dirname(nginx_path)
                nginx_dir = os.path.dirname(nginx_sbin_dir)
                nginx_dir_conf = os.path.join(nginx_dir, 'conf')
                self.nginx_dir = nginx_dir_conf
                self.format_data('%s/nginx.conf' % nginx_dir_conf)
            else:
                print {'error': 0}
        else:
            print {'error': 0}

    def get_read(self, nginx_conf):
        if os.path.exists(nginx_conf):
            with open(nginx_conf) as fs:
                f = fs.readlines()
                for line in f:
                    if "include" in line and "conf" in line and not '#' in line:
                        fp = line.split()[1].strip(';')
                        if fp.endswith("*.conf"):
                            if fp.startswith("/"):
                                if "/conf/" in fp:
                                    fp_dir = os.path.join(self.nginx_dir, fp.split("/conf/")[-1].split("*.")[0])
                                    if os.path.exists(fp_dir):
                                        for i in os.listdir(fp_dir):
                                            if i.endswith(".conf"):
                                                fp_path = os.path.join(fp_dir, i)
                                                self.get_read(fp_path)
                            else:
                                fp_dir = os.path.join(self.nginx_dir, fp.split("/")[0])
                                if os.path.exists(fp_dir):
                                    for i in os.listdir(fp_dir):
                                        if i.endswith(".conf"):
                                            fp_path = os.path.join(fp_dir, i)
                                            self.get_read(fp_path)
                        else:
                            if fp.startswith("/"):
                                fp_conf = fp.split("/")[-1]
                                fp_path = os.path.join(self.nginx_dir, fp_conf)
                                self.get_read(fp_path)
                            else:
                                fp = os.path.join(self.nginx_dir, fp)
                                self.get_read(fp)
                    else:
                        self.read_conf = self.read_conf + line

    def format_data(self, nginx_conf):
        ss = []
        ul = []
        self.get_read(nginx_conf)
        if self.read_conf:
            self.read_conf = self.read_conf.replace("\t", " ")
            self.load(self.read_conf)
            format_start = self.get_value(self.get(('http',)))
            for line in format_start:
                sd = {}
                local_list = []
                if isinstance(line, dict):
                    if line['name'] == 'server':
                        server_value = line['value']
                        for s in server_value:
                            if 'server_name' in s:
                                sd['server_name'] = s[1]
                            elif 'listen' in s:
                                sd['port'] = s[1]
                            elif 'rewrite' in s:
                                sd['rewrite'] = s[1]
                            elif 'location' in str(s):
                                temp_dict = {}
                                temp_pass = s['value']
                                for t in temp_pass:
                                    if 'proxy_pass' in t:
                                        temp_dict['name'] = s['param']
                                        temp_dict['proxy_pass'] = t[1]
                                    else:
                                        temp_dict['name'] = s['param']
                                        temp_dict['config'] = s['value']
                                if temp_dict:
                                    local_list.append(temp_dict)
                        if local_list:
                            sd['location'] = local_list
                        ss.append(sd)
                    elif line['name'] == 'upstream':
                        temp_udict = {}
                        temp_udict['name'] = line['param']
                        temp_udict['server'] = line['value']
                        if temp_udict:
                            ul.append(temp_udict)
        print ss
        print ul


if __name__ == '__main__':
    NginxConf()