#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4
#

import os
import re
import sys
import subprocess
import urllib, urllib2
import requests
from bs4 import BeautifulSoup
from urllib2 import urlopen, ProxyHandler, build_opener, install_opener, URLError, HTTPError
import time
from datetime import datetime, timedelta
import json
import base64
import ast
import xml.etree.cElementTree as ET
import inspect
from random import randint
from jenkinsapi.jenkins import Jenkins

sys.path.insert(1, os.path.join(sys.path[0], '..'))

from common.buildtrigger import trigger_info, trigger_next, get_jenkins_build_data
from common.mapping import git_obs_map_full_list
from common.utils import list_files_in_url, unicode_to_str
from common.git import Git, clone_gitproject
from common.send_mail import prepare_mail, makemail
from common.gerrit import GerritEnv
from common.tizen_studio import TizenStudio
from common.workflow import MailSender

def list_all_packages(profile, gerrit_env):

    list_all = []

    if True:
        mapping_list = git_obs_map_full_list(obs_project=profile, staging_project='abs', \
                                             gitcache=os.path.join(os.getenv('WORKSPACE'), 'temp_git_cache'), \
                                             gerrit_hostname=gerrit_env.hostname, \
                                             gerrit_username=gerrit_env.username, \
                                             gerrit_sshport=gerrit_env.sshport)
        for item in mapping_list:
            print item
            if not all(name in ['Project_name', 'Branch_name', \
                    'OBS_project', 'OBS_staging_project', 'OBS_package'] for name in item):
                continue
            prj_name = item['Project_name']
            _branch = item['Branch_name']
            _obs_prj = item['OBS_project']
            _stg = item['OBS_staging_project']
            _pkg = item['OBS_package']
            _brch = ''
            for _br in _branch.split(','):
                if _brch == '' or len(_br) < len(_brch):
                    _brch = _br
            print '  >> Adding %s(%s) %s %s' % (prj_name, _brch, _obs_prj, _pkg)
            list_all.append({'git_path': prj_name, \
                             'branch_name': _brch, \
                             'obs_project': _obs_prj, \
                             'staging_project': _stg, \
                             'package': _pkg})
    return list_all

def build_result_report(build_number):

    build_result = []
    reason = None
    target = None
    branch = None
    obs_project = None
    last_submitter_list = []

    jenkins_server = Jenkins(os.getenv('JENKINS_URL'), os.getenv('JENKINS_USER'), os.getenv('JENKINS_PW'))
    build_abs = jenkins_server[os.getenv('JOB_NAME')].get_build(int(build_number))
    for action in build_abs.get_actions().get('triggeredBuilds'):
        single_job = action.get('url').split('/')[-3]
        single_build_number = int(action.get('number'))
        single_build = jenkins_server[single_job].get_build(single_build_number)
        single_build_result = single_build.get_status()
        print single_job, single_build_number, single_build_result
        sys.stdout.flush()

        if single_build_result != 'SUCCESS':

            # parameters
            package = None
            project = None

            act = single_build.get_actions()
            if act.get('text') and act.get('text').startswith('Submitter: '):
                single_submitter = act.get('text').split('Submitter: ')[-1]
                if single_submitter not in last_submitter_list:
                    last_submitter_list.append(single_submitter)

            for parm in act.get('parameters'):
                if 'name' in parm and parm['name'] == 'TRIGGER_INFO':
                    json = ast.literal_eval(base64.b64decode(parm.get('value')).replace('null', '\"none\"'))
                    reason = json.get('full_build')
                    project = json.get('event').get('GERRIT_PROJECT')
                    target = json.get('obs_project')
                    obs_project = json.get('obs_project')
                    package = json.get('obs_package')
                    branch = json.get('branch')

            single_build_log = single_build.get_console()

            # log trimming
            exp = r'/home/build/tizen-sdk-cli/tools/smart-build-interface/../../platforms/[a-zA-Z-0-9./]{1,}/rootstraps/[a-zA-Z]{1,}-[0-9.]{1,}-(emulator|device).core.private.[0-9_]{1,}'
            single_build_log = re.sub(exp, '{ROOTSTRAP}', single_build_log)
            exp = r'/home/build/tizen-sdk-cli/tools/smart-build-interface/../'
            single_build_log = re.sub(exp, '{BUILDTOOL}', single_build_log)
            if single_build_log.rfind('ERROR: No "profile" tag in property file') != -1:
                single_build_log = single_build_log[single_build_log.rfind('ERROR: No "profile" tag in property file'):]
    
            start_idx = single_build_log.rfind('VM returned [')
            if start_idx <= -1: start_idx = 0
            start_idx = len(single_build_log) - 2048
            if start_idx <= -1: start_idx = 0
            end_idx = single_build_log.rfind('Total time')
            single_build_log = single_build_log[start_idx:end_idx]

            trimmed_log = []
            for line in single_build_log.split('\n'):
                if 'Finished building: ' in line: continue
                if line.endswith('^'): continue
                trimmed_log.append(line)
            single_build_log = '\n'.join(trimmed_log)

            build_result.append({'number': single_build_number, \
                                 'result': single_build_result, \
                                 'project': project, \
                                 'package': package, \
                                 'log': '%s' % single_build_log})
            del single_build_log
        del single_build

    if len(build_result) <= 0:
        return 0

    mymail = MailSender()
    mymail.add_title('ABS Build check %d errors for %s' % (len(build_result), reason))
    mymail.add_message('App Build System(ABS) reports entire project build.\n' \
                       'It is intended for build check with new private rootstrap.\n' \
                       '(Base souce code from the most recent accepted SR)\n\n')
    mymail.add_message('Full build cause: %s\n' % reason)
    mymail.add_message('OBS Target Project: %s\n' % target)
    mymail.add_message('branch: %s\n\n' % branch)

    if os.getenv('GERRIT_INFRA').startswith('public_gerrit'):
        dashboard_url = os.getenv("PUBLIC_DASHBOARD_URL")
    else:
        dashboard_url = os.getenv("DASHBOARD_URL")

    mymail.add_message('\nFor detailed info, please visit %s/abs_rbs.code?rbs_only=1&project=%s\n\n' \
                       % (dashboard_url, target))

    log_size = 0
    for x in build_result:
        sys.stdout.flush()
        mymail.add_message('\n\n[ %s ] [%s]\n=========' % (x.get('project'), x.get('result')))
        #mymail.add_message(x.get('log'))
        log_size += len(x.get('log'))
    print 'Log Size: %d' % log_size

    mymail.add_message('\n\n--------------------------------------------------------\n'\
                       'Automatically generated by backend service.\n'\
                       'Please DO NOT Reply!')

    mailing_list = os.getenv('ABS_MAILINGLIST').split(',')
    mailing_list.extend(ast.literal_eval(os.getenv('ABS_MAILINGLIST_2')).get(obs_project).split(','))
    if len(last_submitter_list) > 0:
        mailing_list.extend(last_submitter_list)
    mymail.add_receiver(filter(None, mailing_list))

    mymail.send_mail()

    return 2

def main(new_rs, gerrit_name):

    if os.getenv('BUILD_RESULT_REPORT', None):
        return build_result_report(os.getenv('BUILD_RESULT_REPORT'))

    if new_rs is None or new_rs == '' or gerrit_name is None or gerrit_name == '':
        ti = trigger_info(os.getenv('TRIGGER_INFO'))
        new_rs = ti.get('NEW_ROOTSTRAP')
        gerrit_name = ti.get('GERRIT_INFRA')

    assert new_rs
    assert new_rs.startswith('http')

    if gerrit_name.startswith('public_gerrit'):
        gerrit_infra = 'PUBLIC'
        gerrit_env = GerritEnv('PUBLIC_')
    else:
        print 'LOCAL abs no longer supported'
        return 0
        #gerrit_infra = 'LOCAL'
        #gerrit_env = GerritEnv('')

    profiles = os.getenv('ABS_SUPPORTED_PROJECTS').split(',')
    trigger_arg = ''

    kvm_root = '/'.join(os.getenv('ABS_VM_IMAGE').split('/')[:-1])
    pattern = r'tizen[a-zA-Z_-]*[0-9]{8}.[0-9]{1,2}'

    new_rootstrap_url = new_rs
    trigger_arg = new_rs

    rs_version = re.match(r'.*\/(.*-.*_[0-9.]{1,})\/.*', new_rs).group(1)
    print 'new_rs: %s' % new_rs
    print 'rs_version: %s' % rs_version 

    profiles_to_update = []

    for x in os.getenv('ABS_SUPPORTED_PROJECTS').split(','):
        expr = '(%s)_(\d{8}).([0-9]+)' % (x.lower().replace(':', '-'))
        if re.search(expr, new_rs):
            profiles_to_update = [x]
            break
    print 'profiles_to_update:%s' % profiles_to_update

    assert profiles_to_update

    index = 0
    for up in profiles_to_update:
        print 'trigger %s' % up
        ret_prop = ast.literal_eval(os.getenv('ABS_PROJECT_VM_MAP')).get(up)
        vm_image = ret_prop.split(',')[0]
        supported_profiles = ret_prop.split(',')[1].split('|')

        meta_script_map = ast.literal_eval(os.getenv('ABS_CLI_SCRIPT_GIT_MAP'))
        meta_script = meta_script_map.get('default')
        if meta_script_map.get(up, None) is not None:
            meta_script = meta_script_map.get(up)
        print 'meta_script:%s' % meta_script

        my_tizen_studio = TizenStudio(vm_image, meta_script)

        image_to_check = my_tizen_studio.update_rootstrap(new_rs, rs_version, profiles=supported_profiles)
        if image_to_check is None:
            continue
        #image_to_check = 'TizenStudio_18.04.3'
        todo_list = list_all_packages(up, gerrit_env)
        for single_dict in todo_list:
            index += 1
            print '\n%s' % single_dict
            trigger_data = {'obs_project': single_dict.get('obs_project'), \
                            'obs_package': single_dict.get('package'), \
                            'source': {'package': single_dict.get('git_path').split('/')[-1], \
                                       'branch': single_dict.get('branch_name'), \
                                       'git_path': single_dict.get('git_path'), \
                                       'tag': single_dict.get('commitid', None)}, \
                            'full_build': rs_version, \
                            'event': {'GERRIT_EVENT_ACCOUNT_EMAIL': 'abs.robot@tizen.org', \
                                      'GERRIT_EVENT_ACCOUNT_NAME': 'abs-robot', \
                                      'GERRIT_PROJECT': single_dict.get('git_path'), \
                                      'GERRIT_NEWREV': single_dict.get('commitid', None)}, \
                            'type': 'BUILD_CHECK', \
                            'tag': 'build-check', \
                            'branch': single_dict.get('branch_name'), \
                            'revision': 'build-check', \
                            'gerrit_infra': gerrit_infra, \
                            'index': str(index)}
            print 'ABS build for %s initiated.' % (trigger_data['source']['package'])
            trigger_next('ABS_BUILD_CHECK_%d_%d_%s' \
                         % (int(os.getenv('BUILD_NUMBER')), index, trigger_data['source']['package']), \
                         trigger_data)

    trigger_next('ABS_BUILD_RESULT', {'Empty': 'Blank'}, \
                 extra_params={'GERRIT_INFRA': gerrit_name, 'BUILD_RESULT_REPORT': os.getenv('BUILD_NUMBER')})

if __name__ == '__main__':

    sys.exit(main(os.getenv('NEW_ROOTSTRAP'), os.getenv('GERRIT_INFRA')))

