#!/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 job is triggered by gerrit submit ref update event for preloaded app.
   It will generate tizen app package(.tpk) and requests prerelease routine.
"""

import os
import sys
import shutil
import re
import glob
import zipfile
import ast
import base64
import json
import traceback

from datetime import datetime
from random import randint
from time import sleep
import xml.etree.cElementTree as ElementTree

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

from common.utils import parse_link
from common.mapping import git_obs_map
from common.git import Git, clone_gitproject
from common.gerrit import Gerrit, is_ref_deleted, GerritEnv
from common.buildservice import BuildService
from common.prerelease import get_prerelease_project_name
from common.buildtrigger import trigger_info, trigger_next
from common.send_mail import prepare_mail
from common.workflow import find_specfile, parse_specfile
from common.utils import unicode_to_str

from common import buildmonitor_db
from common.buildmonitor_extention import BuildMonitorExtention

# set default char-set endcoding to utf-8
reload(sys)
sys.setdefaultencoding('utf-8') # pylint: disable-msg=E1101

def parse_input_parameters(param):
    _ret = unicode_to_str(json.loads(base64.b64decode(param)))
    print _ret
    return _ret

def update_tizen_studio(param):

    tizen_studio_version = param.get('version')
    tizen_studio_distribution = param.get('distribution')

    query = 'SELECT id FROM tizen_studio WHERE version=%s AND distribution=%s'
    tizen_studio_id = buildmonitor_db.get_value_from_query_data(query, (tizen_studio_version, tizen_studio_distribution))

    if tizen_studio_id == 0:
        query = 'INSERT INTO tizen_studio (version, distribution) VALUES(%s, %s)'
        buildmonitor_db.do_query(query, (tizen_studio_version, tizen_studio_distribution))

def update_rootstrap_status(bm_ext, param):

    event_info = parse_input_parameters(param)
    project           = event_info.get('project', None)
    rootstrap_version = event_info.get('rootstrap_version', None).replace('.','_')
    status            = event_info.get('status', None)
    reason            = event_info.get('reason', None)

    # Find main project id
    query = 'SELECT id FROM main_project WHERE name=%s'
    main_project_id = buildmonitor_db.get_value_from_query_data(query, (project,))

    # Find exiting item
    query = 'SELECT id FROM rootstrap_status WHERE main_project_id=%s AND name=%s'
    existing_id = buildmonitor_db.get_value_from_query_data(query, (main_project_id, rootstrap_version))

    # Insert or Update item
    if existing_id == 0:
        query = 'INSERT INTO rootstrap_status (main_project_id, name, status, status_reason) VALUES(%s, %s, %s, %s)'
        buildmonitor_db.do_query(query, (main_project_id, rootstrap_version, status, reason))
    else:
        query = 'UPDATE rootstrap_status SET status=%s, status_reason=%s WHERE id=%s LIMIT 1'
        buildmonitor_db.do_query(query, (status, reason, existing_id))

def update_repository(repo_name):
    query = "INSERT INTO git_repository (name) SELECT * FROM (SELECT %s) AS tmp \
             WHERE NOT EXISTS (SELECT name FROM git_repository WHERE name = %s) LIMIT 1"
    buildmonitor_db.do_query(query, (repo_name, repo_name))


def update_commit(git_path_id, commit_id, commit_date, committer, commit_message):
    query = "INSERT INTO git_commit (git_repository_id, commit_id, committer, commit_date, commit_message) \
             SELECT * FROM (SELECT %s, %s, %s, %s, %s) AS tmp \
             WHERE NOT EXISTS (SELECT git_repository_id, commit_id \
             FROM git_commit WHERE git_repository_id = %s AND commit_id = %s) \
             LIMIT 1"
    buildmonitor_db.do_query(query, ('%d' % git_path_id, commit_id, committer, commit_date, commit_message, '%d' % git_path_id, commit_id))

def update_tag(git_commit_id, tag_name, tag_revision, tagger, tag_date, tag_message):
    query = "INSERT INTO git_tag (git_commit_id, tag_name, tag_revision, tagger, tag_date, tag_message) \
             SELECT * FROM (SELECT %s, %s, %s, %s, %s, %s) AS tmp \
             WHERE NOT EXISTS (SELECT git_commit_id, tag_revision \
             FROM git_tag WHERE git_commit_id = %s AND tag_revision = %s) LIMIT 1"
    buildmonitor_db.do_query(query, ('%d' % git_commit_id, tag_name, tag_revision, tagger, tag_date, tag_message, '%d' % git_commit_id, tag_revision))

def get_git_path_id(git_path):
    query = 'SELECT id FROM git_repository WHERE name=%s'
    git_path_id = buildmonitor_db.get_value_from_query_data(query, (git_path, ))
    return git_path_id

def get_git_commit_id(git_path, commit_id):
    query = 'SELECT gc.id FROM git_commit gc, git_repository gr WHERE gr.name=%s AND gc.git_repository_id=gr.id AND gc.commit_id=%s'
    git_commit_id = buildmonitor_db.get_value_from_query_data(query, (git_path, commit_id))
    return git_commit_id

def get_git_tag_id(git_commit_id, tag_name, tag_revision):
    query = 'SELECT id FROM git_tag WHERE git_commit_id=%s AND tag_name=%s AND tag_revision=%s'
    git_tag_id = buildmonitor_db.get_value_from_query_data(query, (git_commit_id, tag_name, tag_revision))
    return git_tag_id

def update_commit_tag_for_abs(bm_ext, param):

    event_info = parse_input_parameters(param)

    git_path          = event_info.get('git_path', None)

    commit_id         = event_info.get('commit_id', None)
    commit_date       = event_info.get('commit_date', None)
    committer         = event_info.get('committer', None)
    commit_message    = event_info.get('commit_message', None)

    tag_name          = event_info.get('tag_name', None)
    tag_revision      = event_info.get('tag_revision', None)
    tagger            = event_info.get('tagger', None)
    tag_date          = event_info.get('tag_date', None)
    tag_message       = event_info.get('tag_message', None)

    if git_path is not None:
        update_repository(git_path)

    if len(commit_date.split(' ')) >= 3:
        commit_date = ' '.join(commit_date.split(' ')[:2])
    if len(tag_date.split(' ')) >= 3:
        tag_date = ' '.join(tag_date.split(' ')[:2])

    #Find git repo id
    git_path_id = get_git_path_id(git_path)
    assert git_path_id != 0

    if git_path_id != 0 \
        and commit_id is not None \
        and commit_date is not None \
        and committer is not None \
        and commit_message is not None:
        branch = '/'.join(tag_name.replace('submit/','').split('/')[:-1])
        bm_ext.update_git_commit_strict(git_path, commit_id, committer, commit_date, commit_message, branch)

    #Find commit id
    git_commit_id = get_git_commit_id(git_path, commit_id)
    assert git_commit_id != 0

    if tag_name is not None and not tag_name.startswith('refs/tags/'):
        tag_name = 'refs/tags/%s' % tag_name
    if git_commit_id != 0 \
        and tag_name is not None \
        and tag_revision is not None \
        and tagger is not None \
        and tag_date is not None \
        and tag_message is not None:
        bm_ext.update_git_tag_strict(git_commit_id, tag_name, tag_revision, tagger, tag_date, tag_message)

    #Find tag id
    git_tag_id = get_git_tag_id(git_commit_id, tag_name, tag_revision)
    assert git_tag_id != 0

    return [git_path_id, git_commit_id, git_tag_id]

def reform_param(param):
    return param.replace('None', '""')

def start_abs(bm_ext, param):

    event_info = parse_input_parameters(param)

    git_path_id, git_commit_id, git_tag_id = update_commit_tag_for_abs(bm_ext, param)
    print '\n\n========'
    print git_path_id, git_commit_id, git_tag_id
    print '========\n\n'

    #TODO: Update abs status
    update_abs_status(bm_ext,
                      event_info.get('type'), \
                      event_info.get('project'), \
                      event_info.get('status'), \
                      event_info.get('status_reason'), \
                      git_tag_id, \
                      event_info.get('tpk_git_tag'), \
                      event_info.get('obs_package_name'), \
                      event_info.get('rootstrap_version'), \
                      event_info.get('tizen_studio_version'), \
                      event_info.get('tizen_studio_distribution'))

def update_abs_status(bm_ext, mode, main_project, status, status_reason, source_git_tag_id, tpk_git_tag, obs_package_name, rootstrap_version, tizen_studio_version, tizen_studio_distribution):

    # Find main project id
    query = 'SELECT id FROM main_project WHERE name=%s'
    main_project_id = buildmonitor_db.get_value_from_query_data(query, (main_project, ))

    if main_project_id == 0:
        assert False

    # Find latest rootstrap version if input is null
    if rootstrap_version is not None:
        rootstrap_version = rootstrap_version.replace('.','_')
    if rootstrap_version is None:
        query = 'SELECT rs.name FROM rootstrap_status rs, main_project mp WHERE mp.id=rs.main_project_id AND mp.name=%s order by rs.id desc limit 1'
        rootstrap_version = buildmonitor_db.get_value_from_query_data(query, (main_project,))
    assert rootstrap_version != 0

    # Find rootstrap id
    query = 'SELECT rs.id FROM rootstrap_status rs, main_project mp WHERE mp.name=%s AND rs.main_project_id=mp.id AND rs.name=%s'
    rootstrap_id = buildmonitor_db.get_value_from_query_data(query, (main_project, rootstrap_version))
    if rootstrap_id == 0:
        myparam = {'project': main_project,
                   'rootstrap_version': rootstrap_version,
                   'status': 'succeeded'}
        update_rootstrap_status(bm_ext, json.dumps(myparam))
        rootstrap_id = buildmonitor_db.get_value_from_query_data(query, (main_project, rootstrap_version))
    assert rootstrap_id != 0

    # Find existing item
    query = 'SELECT abs.id FROM abs_status abs, main_project mp WHERE abs.type=%s AND mp.name=%s AND abs.main_project_id=mp.id AND abs.source_git_tag_id=%s AND abs.rootstrap_id=%s'
    abs_status_id = buildmonitor_db.get_value_from_query_data(query, (mode, main_project, source_git_tag_id, rootstrap_id))

    # Find tizen_studio id
    if tizen_studio_version is None:
        tizen_studio_version = 'Tizen CLI 0.0.0'
    if tizen_studio_distribution is None:
        tizen_studio_distribution = 'default'
    query = 'SELECT id FROM tizen_studio WHERE version=%s AND distribution=%s'
    tizen_studio_id = buildmonitor_db.get_value_from_query_data(query, (tizen_studio_version, tizen_studio_distribution))
    if tizen_studio_id == 0:
        myparam = {'version': tizen_studio_version,
                   'distribution': tizen_studio_distribution} 
        update_tizen_studio(myparam)
        tizen_studio_id = buildmonitor_db.get_value_from_query_data(query, (tizen_studio_version, tizen_studio_distribution))
    assert tizen_studio_id != 0

    if abs_status_id == 0:
        query = 'INSERT INTO abs_status (type, main_project_id, status, status_reason, source_git_tag_id, tpk_git_tag, obs_package_name, rootstrap_id, tizen_studio_id) VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s)'
        buildmonitor_db.do_query(query, (mode, main_project_id, status, status_reason, source_git_tag_id, tpk_git_tag, obs_package_name, rootstrap_id, tizen_studio_id))
    else:
        query = 'UPDATE abs_status SET status=%s, status_reason=%s, tpk_git_tag=%s, obs_package_name=%s, rootstrap_id=%s, tizen_studio_id=%s WHERE id=abs_status_id LIMIT 1'
        query_data = ()
        query = 'UPDATE abs_status SET '
        if status:
            query = '%s status=%%s,' % query
            query_data += (status,)
        if status_reason:
            query = '%s status_reason=%%s,' % query
            query_data += (status_reason,)
        if source_git_tag_id and source_git_tag_id != 0:
            query = '%s source_git_tag_id=%%s,' % query
            query_data += (source_git_tag_id,)
        if tpk_git_tag:
            query = '%s tpk_git_tag=%%s,' % query
            query_data += (tpk_git_tag,)
        if obs_package_name:
            query = '%s obs_package_name=%%s,' % query
            query_data += (obs_package_name,)
        if rootstrap_id and rootstrap_id != 0:
            query = '%s rootstrap_id=%%s,' % query
            query_data += (rootstrap_id,)
        if tizen_studio_id and tizen_studio_id != 0:
            query = '%s tizen_studio_id=%%s,' % query
            query_data += (tizen_studio_id,)
        query = query[:-1]
        query = '%s WHERE id=%%s LIMIT 1' % query
        query_data += (abs_status_id,)
        buildmonitor_db.do_query(query, query_data)

def finish_abs(bm_ext, param):

    git_path_id, git_commit_id, git_tag_id = update_commit_tag_for_abs(bm_ext, param)
    print '\n\n========'
    print git_path_id, git_commit_id, git_tag_id
    print '========\n\n'

    #TODO: Update abs status

def main():

    event_type = os.getenv('EVENT_TYPE', None)
    rootstrap_version = os.getenv('ROOTSTRAP_VERSION', None)

    buildmonitor_db.connect_db()
    bm_ext = BuildMonitorExtention()

    try:
        #TODO: Update RBS status
        if event_type == 'ROOTSTRAP_UPDATED':
            update_rootstrap_status(bm_ext, os.getenv(event_type))
        elif event_type == 'START_ABS':
            start_abs(bm_ext, os.getenv(event_type))
        elif event_type == 'FINISH_ABS':
            finish_abs(bm_ext, os.getenv(event_type))
    except Exception as err:
        print traceback.format_exc()
        buildmonitor_db.disconnect_db()
        print repr(err)
        return -1

    buildmonitor_db.disconnect_db()

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

