#!/usr/bin/env python
#
# Copyright (c) 2014, 2015, 2016 Samsung Electronics.Co.Ltd.
#
# 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.
#
"""This script is used to update git-ref-mapping"""

import os
import sys
import json
import re
import requests

from common.buildtrigger import trigger_info
from common.git import Git, clone_gitproject
from common.prerelease import is_prerelease_project

from gbp.git.args import GitArgs

import xml.etree.cElementTree as ElementTree

GIT_FILE_NAME = 'prerelease.description'

class LocalError(Exception):
    """Local error exception."""
    pass

def get_manifest_filelists_snapshot(profile, request_url, timeout=5, group=None):
        """ get manifest filelists from snapshot"""
        #p = re.compile(r'alt=\"\[(TXT|DIR|   )]*\]\".*<a href=\"(.*)\">')
        p = re.compile(r'.*<a href=\"(.*)\">')

        if not request_url:
            return {}
        print request_url
        # get data from url
        for loop in range(10):
            try:
                f = requests.get(request_url,
                                 auth=(profile['snapshot_username'],
                                       profile['snapshot_password']),
                                 timeout=timeout)
                if f.status_code == 200:
                    break
            except requests.exceptions.Timeout as e:
                print(e)
                continue
            except requests.exceptions.ConnectionError as e:
                print(e)
                continue
            except Exception as e:
                print(e)
                raise Exception('exception from get manifest filelists')

        results = {}
        exclude_pkgs = []
        found_links = p.findall(f.text)
        for link in found_links:
            if link == '../':
                continue
            if not link.endswith('.xml'):
                continue
            manifest_url = os.path.join(request_url, link)
            f = requests.get(manifest_url,
                             auth=(profile['snapshot_username'],
                                   profile['snapshot_password']),
                             timeout=timeout)
            try:
                tree = ElementTree.fromstring(f.text)
            except ElementTree.ParseError:
                raise ElementTree.ParseError
            for result in tree.findall('project'):
                if '_preloadapp.xml' in link:
                    exclude_pkgs.append(''.join(result.get('path')))
                else:
                    results[''.join(result.get('path'))] = result.get('revision')

        if group == 'abs':
            preloadapp_pkgs = {}
            for app in exclude_pkgs:
                preloadapp_pkgs[app] = results[app]
            return preloadapp_pkgs

        return results


def prerelease_info_update(saved_info):
    """
    Prerelease info update
    """
    project = saved_info.get('obs_url').split('project=')[-1]
    if project is None:
        raise LocalError('Please check the project (%s)' \
                         % (project))
    print '\n\"Title\": \"%s\"' % project

    if not is_prerelease_project(project):
        print '%s is not prerelease project' % project
        return 1

    try:
        target_project, branch = \
            re.search(r'home:prerelease:(.*):submit:(.*):[0-9]{8}.[0-9]{6}', \
                      project).groups()
        # Fix Branch name: search a branch in project name.
        branch = branch.replace(':','/')
    except Exception as err:
        raise LocalError('Cannot determine target branch (%s)' % err)

    # Append linked built packages
    manifest_list = []
    try:
        manifest_list = get_manifest_filelists_snapshot( \
                            {'snapshot_username': '', \
                             'snapshot_password': ''}, \
                            os.path.join(saved_info.get('download_url'), 'builddata/manifest'), \
                            timeout=5, group=None).keys()
    except Exception as err:
        print repr(err)
    for t in saved_info.get('projects', []):
        if t in manifest_list:
            manifest_list.remove(t)
    saved_info['linked_build_projects'] = manifest_list

    #TODO: tizen_{profile}_tpk branch hack
    if branch.endswith('_tpk') or branch.endswith('_wgt'):
        abs_branch_postfix = branch[-4:]
        if os.getenv('ABS_SUPPORTED_PROFILES', None):
            for sp in os.getenv('ABS_SUPPORTED_PROFILES').split(','):
                branch = branch.replace('_%s%s' % (sp.lower(), abs_branch_postfix), '')
        #branch = branch.split('_%s_tpk' % target_project.split(':')[-1].lower())[0]
    print 'We have [%s] [%s]' % (target_project, branch)

    prjdir = os.path.join(os.getenv('WORKSPACE'), \
                          os.path.basename(os.getenv('TEST_TRIGGER_GIT_PATH')))

    if not clone_gitproject(os.getenv('TEST_TRIGGER_GIT_PATH'), prjdir, \
                            git_cache_dir=os.getenv('GIT_CACHE_DIR')):
        print 'Error cloning %s' % os.getenv('TEST_TRIGGER_GIT_PATH')
        return 2

    saved_info = json.dumps(saved_info)

    mygit = Git(prjdir)
    if mygit.has_branch('origin/' + branch, remote = True):
        mygit.checkout(branch)
    else:
        args = GitArgs('--orphan', branch)
        mygit._git_command('checkout', args.args)
        args = GitArgs('-rf', '.')
        try:
            mygit._git_command('rm', args.args)
        except Exception as err:
            print repr(err)
    if os.path.exists(os.path.join(prjdir, GIT_FILE_NAME)):
        mygit.remove_files(GIT_FILE_NAME)
    with open(os.path.join(prjdir, GIT_FILE_NAME), 'w') as mf:
        mf.write(saved_info)
    mygit.add_files(GIT_FILE_NAME, True)
    try:
        mygit.commit_staged('%s' % project.replace('home:prerelease:',''))
        mygit.push(repo = 'origin', src = branch)
    except Exception as err:
        print '\n** Commit or push to git error, %s\n' % err
        return 4

def snapshot_info_update(saved_info):
    """
    Snapshot info update
    """
    if 'project' not in saved_info:
        raise LocalError('Please check the project ')

    try:
        project = saved_info.get('project', "")
        # Fix Branch name: search a branch in project name.
        branch = project.lower().replace(':','-')
        commitmsg = saved_info.get('build_id', "")
    except Exception as err:
        raise LocalError('Cannot determine target branch (%s)' % err)

    print 'We have [%s] [%s]' % (project, branch)

    prjdir = os.path.join(os.getenv('WORKSPACE'), \
                          os.path.basename(os.getenv('TEST_TRIGGER_GIT_PATH')))

    if not clone_gitproject(os.getenv('TEST_TRIGGER_GIT_PATH'), prjdir, \
                            git_cache_dir=os.getenv('GIT_CACHE_DIR')):
        print 'Error cloning %s' % os.getenv('TEST_TRIGGER_GIT_PATH')
        return 2

    saved_info = json.dumps(saved_info)

    mygit = Git(prjdir)
    if mygit.has_branch('origin/' + branch, remote = True):
        mygit.checkout(branch)
    else:
        args = GitArgs('--orphan', branch)
        mygit._git_command('checkout', args.args)
        args = GitArgs('-rf', '.')
        try:
            mygit._git_command('rm', args.args)
        except Exception as err:
            print repr(err)
    if os.path.exists(os.path.join(prjdir, GIT_FILE_NAME)):
        mygit.remove_files(GIT_FILE_NAME)
    with open(os.path.join(prjdir, GIT_FILE_NAME), 'w') as mf:
        mf.write(saved_info)
    mygit.add_files(GIT_FILE_NAME, True)
    try:
        mygit.commit_staged(commitmsg)
        mygit.push(repo = 'origin', src = branch)
    except Exception as err:
        print '\n** Commit or push to git error, %s\n' % err
        return 4


def main():
    """The main body"""

    saved_info = trigger_info(os.getenv('TRIGGER_INFO'))
    if 'obs_url' in saved_info:
        return prerelease_info_update(saved_info)
    else:
        return snapshot_info_update(saved_info)

if __name__ == '__main__':
    sys.exit(main())

