#!/usr/bin/env python
#
# Copyright (C) 2016 Samsung
#
#    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; version 2
#    of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
"""Apply meta data from file to system."""

import os
import subprocess
import collections
import git_diff_parse

class Server:
    def __init__(self, port, account, url):
        self.port = port
        self.account = account
        self.url = url

class SyntaxError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return self.value

def get_diff_info(dic):
        obj_list = []

        git_diff_parse.git_diff_parse(obj_list)
        for i in range(len(obj_list)):
                for j in range(len(meta_file_list)):
                        if obj_list[i][1] == meta_file_list[j]:
                                dic[meta_file_list[j]].append(obj_list[i][:])
                                break

def get_key_list(dic, readme_file):
    with open('%s' % readme_file, 'r') as lines:
        read_status = False
        cur_file = ''
        for line in lines:
            if line.split(':')[0] == 'Filename':
                cur_file = line.split(':')[1].split('"')[1]
                if cur_file in meta_file_list:
                    read_status = True
                    continue
            if read_status:
                if line.strip() == '':
                    read_status = False
                else:
                    temp = line.strip().split(' ')
                    if temp[len(temp) - 2] + ' ' + temp[len(temp) - 1] == 'Read Only':
                        attr = 1
                    else:
                        attr = 0
                    dic[cur_file][line.strip()[0]] = attr

def init_info(file_list, readme_file, sdir):
    global meta_file_list
    global meta_info
    global key_list
    global scripts_dir

    meta_file_list = []
    meta_info = {}
    key_list = {}
    scripts_dir = sdir

    for i in range(len(file_list)):
        meta_file_list.append(file_list[i])
        meta_info[file_list[i]] = []
        key_list[file_list[i]] = collections.OrderedDict()

    get_diff_info(meta_info)
    get_key_list(key_list, readme_file)

    global group_list
    global changed_git_list
    global description_list

    group_list = {'A' : 'Architects', 'M' : 'Maintainers', 'I' : 'Integrators', 'R' : 'Reviewers'}
    git_domain = {}
    changed_git_list = set()
    description_list = collections.OrderedDict()
    description_list['D'] = 'Domain'
    description_list['O'] = 'Owners'
    description_list['L'] = 'Licenses'
    description_list['C'] = 'Comments'

def print_message(status, fn, ln, lm, comment):
    if status == 'OK':
        print("[%s, %d, OK] %s - %s" % (fn, ln, lm, comment))
    else:
        print("[%s, %d, Error] %s - %s" % (fn, ln, lm, comment))
        return "[%s, %d, Error] %s - %s" % (fn, ln, lm, comment)

def find_section(line_num, index):
        return subprocess.check_output('%s/check_section.sh %d %s' % (scripts_dir, line_num, index), shell = True)

def arrange_desc(desc_list, git_list):
    git_desc_list = {}
    ret_list = []

    for i in range(len(git_list)):
        for key in description_list.keys():
            git_desc_list[key] = []
        for j in range(len(desc_list[i])):
            if len(desc_list[i][j]) == 0:
                continue
            key = desc_list[i][j][0]
            if key in git_desc_list:
                git_desc_list[key].append(desc_list[i][j].split('%s: ' % key)[1])

        final_desc = ""
        for key in description_list.keys():
            if len(git_desc_list[key]) == 0:
                continue
            final_desc = final_desc + description_list[key] + ': '
            for k in range(len(git_desc_list[key])):
                final_desc = final_desc + git_desc_list[key][k] + ', '
            final_desc = final_desc.rstrip(', ')
            final_desc = final_desc + '; '
        final_desc = final_desc.rstrip(' ')

        ret_list.append([git_list[i], final_desc])

    return ret_list

def get_desc_list(git_list):
    ret_list = []
    for i in range(len(git_list)):
        ret_list.append(subprocess.check_output('%s/get_git_desc_info.sh %s' % (scripts_dir, git_list[i]), shell = True))
        ret_list[i] = ret_list[i].strip().split(';')
        del ret_list[i][len(ret_list[i]) - 1]
    return arrange_desc(ret_list, git_list)

def get_domain_info(name, server):
    return subprocess.check_output("ssh -p %s %s@%s gerrit ls-projects --has-acl-for \'%s\ -\ Maintainers\' --type ALL | grep scm/acls/domain_" % (server.port, server.account, server.url, name.replace(' ', '\ ')), shell = True).strip()

def get_submit_type_info(git):
    git_line = int(subprocess.check_output("cat git-trees | grep -n %s" % git, shell = True).strip().split(':')[0])
    return subprocess.check_output("head -%d git-trees | tail -1" % (git_line + 2), shell = True).strip()

def apply_git_trees(desc_list, server, cur_file):
    for i in range(len(desc_list)):
        git = desc_list[i][0]
        desc = desc_list[i][1].replace('\\n', '\\\r\\\n').replace('; ', '; \\\r\\\n').replace(' ', '\ ').replace('&', '\&')
        domain_info = get_domain_info(desc_list[i][1].split(';')[0].split('Domain:')[1].strip(), server)
        submit_type_info = get_submit_type_info(git)
        submit_type_info = submit_type_info.split('%s: ' % submit_type_info[0])[1]

        line_num = int(subprocess.check_output("grep -n %s %s" % (git, cur_file), shell = True).split(':')[0])
        line_message = "G: " + git

        ## set description
        ret = os.system('ssh -p %s %s@%s gerrit set-project %s -d "%s"' % (server.port, server.account, server.url, git, desc))
        if ret:
            raise SyntaxError(print_message('Error', cur_file, line_num, line_message, "%s description setting is failed." % git))
        else:
            print_message('OK', cur_file, line_num, line_message, 'apply_git_trees - description')

        ## set domain
        ret = os.system('ssh -p %s %s@%s gerrit set-project-parent %s --parent %s' % (server.port, server.account, server.url, git, domain_info))
        if ret:
            raise SyntaxError(print_message('Error', cur_file, line_num, line_message, "%s can't assign to %s." % (git, domain_info)))
        else:
            print_message('OK', cur_file, line_num, line_message, 'apply_git_trees - domain')

        ## set submit type
        ret = os.system('ssh -p %s %s@%s gerrit set-project %s -t %s' % (server.port, server.account, server.url, git, submit_type_info))
        if ret:
            raise SyntaxError(print_message('Error', cur_file, line_num, line_message, "%s can't set as %s." % (git, submit_type_info)))
        else:
            print_message('OK', cur_file, line_num, line_message, 'apply_git_trees - submit type')


def apply_member_to_domain(cur_file, obj, line_num, line_message, cur_domain, server):
    if obj[0] == '-':
        opt = '-r'
    elif obj[0] == '+':
        opt = '-a'

    group = cur_domain + ' - ' + group_list[obj[1]]
    mgroup = group.replace(' ', '\ ').replace('&', '\&')
    user = line_message.split('%s: ' % line_message[0])[1]
#    if '<' in user:
#        if user.split('<')[1].split('>')[0] == 'n/a':
#            user = user.split('<')[0].strip() + ' ' + user.split('>')[1].strip()
    muser = user.replace(' ', '\ ').replace('<', '\<').replace('>', '\>')

    ret = os.system('ssh -p %s %s@%s gerrit set-members \"%s\" %s \"%s\"' % (server.port, server.account, server.url, mgroup, opt, muser))
    if ret:
        raise SyntaxError(print_message('Error', cur_file, line_num, line_message, "%s isn't applied in %s." % (user, group)))
    else:
        print_message('OK', cur_file, line_num, line_message, 'apply_member_to_domain')

def apply_to_each_system(cur_file, obj, line_num, line_message, cur_section, server):
    if cur_file == 'domains':
        apply_member_to_domain(cur_file, obj, line_num, line_message, cur_section, server)
    elif cur_file == 'git-trees':
        ## git-trees will be applied at once later.
        changed_git_list.add(cur_section)

def apply_each_object(server):
    for cur_file in meta_info.keys():
        for i in range(len(meta_info[cur_file])):
            for j in range(len(meta_info[cur_file][i])):
                if j > 3:
                    obj = meta_info[cur_file][i][j]
                    if len(obj) == 0:
                        continue
                    elif obj[0] == '+' or obj[0] == '-':
                        line_num = int(meta_info[cur_file][i][3].split(',')[0]) + j - 4
                        line_message = "%s" % obj[0].join(obj.split(obj[0])[1:len(obj)])

                        if len(obj) > 1:
                            cur_section = find_section(line_num, meta_info[cur_file][i][2]).strip().split('%s: ' % list(key_list[cur_file].keys())[0])[1]
                            apply_to_each_system(cur_file, obj, line_num, line_message, cur_section, server)

def apply_to_system(meta_files, readme_file, sdir, port, account, url):
    init_info(meta_files, readme_file, sdir)

    try:
        apply_each_object(Server(port, account, url))

        ## git descriptions are applied at once.
        final_desc_list = get_desc_list(list(changed_git_list))
        apply_git_trees(final_desc_list, Server(port, account, url), 'git-trees')

    except SyntaxError, ret:
        return ret

    return 0
