#!/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.
#

import re
import os
import sys
import shutil
import subprocess

from common.buildtrigger import trigger_info
from common.dep_parse import make_dep_graph, set_obs_environment, set_mysql_environment
from common.utils import sync
from common.buildservice import BuildService
from common.prerelease import get_prerelease_project_name, prerelease_enabled, get_info_from_prerelease_name
from common.snapshot import Snapshot, SnapshotError
from common.backenddb import BackendDB

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

class RuntimeException(Exception):
    """Local error handler"""
    pass

def create_build_progress_dep_graph(build, obs_project, content):
    sync_dest_base = os.getenv('PATH_REPO_BASE')


    # copy vis and dep_graph dirs.
    vis_sync_dest = os.path.join(sync_dest_base, ".dep_graph/vis")
    if not os.path.exists(vis_sync_dest):
        vis_dir = os.path.join(os.getenv("WORKSPACE"), "jenkins-scripts/vis")
        sync(vis_dir, vis_sync_dest)

    dep_graph_sync_dest = os.path.join(sync_dest_base, ".dep_graph/dep_graph")
    if not os.path.exists(dep_graph_sync_dest):
        dep_graph_dir = os.path.join(os.getenv("WORKSPACE"), "jenkins-scripts/dep_graph")
        sync(dep_graph_dir, dep_graph_sync_dest)

    vis_dir = "../../../../vis"
    dep_graph_dir = "../../../../dep_graph"
    template_filename="jenkins-scripts/common/dep_graph.html.template_simple"

    repo = content.get("repo")
    arch = content.get("arch")

    graph_root_dir = os.path.join(os.getenv('WORKSPACE'), arch)
    #make directories if not existed.
    os.makedirs(graph_root_dir)
    print "graph_root_dir = %s" % graph_root_dir

    packages_to_be_built = []
    if re.match("^home:prerelease:", obs_project) or re.match("^home:trbs:", obs_project):
      info=build.get_info(obs_project)
      packages_to_be_built = info['packages']

    xml = build.get_dependson(obs_project, repo, arch, None, None)
    filename = os.path.join(graph_root_dir, "builddepinfo.xml")
    with open(filename, 'w') as xml_file:
        xml_file.write(xml)

    set_obs_environment(os.getenv("OBS_API_URL"),
                        os.getenv("OBS_API_USERNAME"),
                        os.getenv("OBS_API_PASSWD"),
                        obs_project,
                        repo,
                        arch)
    set_mysql_environment(os.getenv("BUILDMONITOR_IP"),
        os.getenv("BUILDMONITOR_USER"),
        os.getenv("BUILDMONITOR_PASS"),
        os.getenv("BUILDMONITOR_NAME"),
        "0")

    make_dep_graph(filename, graph_root_dir,
                   vis_dir, dep_graph_dir, template_filename,
                   packages_to_be_built)

    sync_latest = os.path.join(sync_dest_base,
                             ".dep_graph",
                             obs_project)
    sync_dest = os.path.join(sync_latest,
                             content.get("build_project_id"),
                             repo)

    print "sync_dest = %s" % sync_dest

    # sync to download server
    if not os.path.exists(sync_dest):
        os.makedirs(sync_dest)

    sync_final_dir = os.path.join(sync_dest, os.path.basename(graph_root_dir))
    print "sync_dir = %s" % sync_final_dir
    if( os.path.exists(sync_final_dir) ):
        shutil.rmtree(sync_final_dir)

    sync(graph_root_dir, sync_dest)

    # make latest link
    latest = os.path.join(sync_latest, "latest")
    if os.path.exists(latest) or os.path.islink(latest):
        os.unlink(latest)
    os.symlink(content.get("build_project_id"), latest)

def create_build_progress_dep_graph_post(build, obs_project, backenddb, content):
    print "creating build_progress_dep_graph..."

    sync_out_dir = os.path.join(os.getenv('WORKSPACE'),
                                    'outdir')

    repo_base=os.getenv("PATH_REPO_BASE")
    live_repo_base = os.getenv('PATH_LIVE_REPO_BASE')


    try:
        snapshot = Snapshot(backenddb, repo_base, obs_project=obs_project)
    except SnapshotError, err:
        raise LocalError("Error getting snapshot info: %s" % str(err))

    targets = snapshot.targets
    live_repo_path = os.path.join(live_repo_base,
                                  obs_project.replace(':', ':/'))
    build_id_arr=snapshot.build_id.split('.')
    build_id_arr[-1] = str(int(build_id_arr[-1])+1)
    new_build_id = '.'.join(build_id_arr)
    sync_dest = os.path.join(repo_base,
                             snapshot.dir, new_build_id)

    print "sync_dest = %s" % sync_dest
    #if sync_dest is already exists, skip this process.
    if sync_dest.startswith('rsync:'):
        cmd = "rsync %s" % (sync_dest)
        try:
            ret = subprocess.call(cmd, shell=True)
            if ret == 0:
                print "directory already exist. exiting."
                return
        except OSError as err:
            raise RuntimeException("Execution of %s failed: %s" %
                                   (cmd, str(err)))
    elif sync_dest.startswith('ssh:'):
        sync_dest = sync_dest.replace("ssh://", "")
        splices = sync_dest.split(':')
        cmd = "ssh %s ls %s" % (splices[0], splices[1])
        try:
            ret = subprocess.call(cmd, shell=True)
            if ret == 0:
                print "directory already exist. exiting."
                return
        except OSError as err:
            raise RuntimeException("Execution of %s failed: %s" %
                                   (cmd, str(err)))
    else:
        if( os.path.exists(sync_dest) ):
            print "directory %s is already exist! skip make_dep_graph." % (sync_dest)
            return
        os.makedirs(sync_dest)

    # first sync to make just directory.
    sync(sync_out_dir, sync_dest)

    graph_root_dir = os.path.join(sync_out_dir, "builddata",
        "depends", "build_progress_dep_graph")

    print "graph_root_dir = %s" % graph_root_dir

    vis_dir = "../../vis"
    dep_graph_dir = "../../dep_graph"
    template_filename="jenkins-scripts/common/dep_graph.html.template_simple"

    # copy vis and dep_graph dirs.
    jenkins_script_dir = os.path.join(os.getenv("WORKSPACE"), "jenkins-scripts")
    shutil.copytree(os.path.join(jenkins_script_dir,"vis"), os.path.join(graph_root_dir, "vis"))
    shutil.copytree(os.path.join(jenkins_script_dir,"dep_graph"), os.path.join(graph_root_dir, "dep_graph"))

    repo_status = build.get_repo_state(obs_project)
    for target_arch,status in repo_status.items():
        repo = target_arch.split("/")[0]
        arch = target_arch.split("/")[1]

        xml = build.get_dependson(obs_project, repo, arch, None, None)
        graph_dest_dir = os.path.join(graph_root_dir, repo, arch)
        if not os.path.exists(graph_dest_dir):
            os.makedirs(graph_dest_dir)
        filename = os.path.join(graph_root_dir, repo, arch, "builddepinfo.xml")
        with open(filename, 'w') as xml_file:
            xml_file.write(xml)

        set_obs_environment(os.getenv("OBS_API_URL"),
                            os.getenv("OBS_API_USERNAME"),
                            os.getenv("OBS_API_PASSWD"),
                            obs_project,
                            repo,
                            arch)

        make_dep_graph(filename, graph_dest_dir,
                       vis_dir, dep_graph_dir, template_filename)

    # sync to donwload server
    sync(sync_out_dir, sync_dest)

def create_build_progress_dep_graph_prerelease(build, obs_project, obs_linked_project, backenddb):
    print "creating build_progress_dep_graph_prerelease..."

    sync_out_dir = os.path.join(os.getenv('WORKSPACE'),
                                    'outdir')

    info=build.get_info(obs_project)
    packages_to_be_built = info['packages']

    repo_base=os.getenv("PATH_REPO_BASE")
    base_url = os.getenv("URL_PUBLIC_REPO_BASE")

    # Make build id from latest snapshot + project suffix
    target_project, tstamp = get_info_from_prerelease_name(obs_project)

    try:
        snapshot = Snapshot(backenddb, repo_base, obs_project=target_project)
    except SnapshotError, err:
        raise LocalError("Error getting snapshot info: %s" % str(err))

    try:
        prerelease = snapshot.get_prerelease(base_url, tstamp)
    except SnapshotError, err:
        raise LocalError("Error getting prerelease info: %s" % str(err))

    sync_dest = os.path.join(repo_base,
                             prerelease.path, prerelease.build_id)
    graph_root_dir = os.path.join(sync_out_dir, "builddata",
        "depends", "build_progress_dep_graph")
    print "graph_root_dir = %s" % graph_root_dir
    print "packages_to_be_built = %s" % packages_to_be_built

    #vis_dir="../../../../../../../../../../../vis";
    #dep_graph_dir="../../../../../../../../../../../dep_graph";
    vis_dir = "../../vis"
    dep_graph_dir = "../../dep_graph"
    template_filename="jenkins-scripts/common/dep_graph.html.template_simple"

    # copy vis and dep_graph dirs.
    jenkins_script_dir = os.path.join(os.getenv("WORKSPACE"), "jenkins-scripts")
    shutil.copytree(os.path.join(jenkins_script_dir,"vis"), os.path.join(graph_root_dir, "vis"))
    shutil.copytree(os.path.join(jenkins_script_dir,"dep_graph"), os.path.join(graph_root_dir, "dep_graph"))

    repo_status = build.get_repo_state(obs_linked_project)
    for target_arch,status in repo_status.items():
        repo = target_arch.split("/")[0]
        arch = target_arch.split("/")[1]

        xml = build.get_dependson(obs_linked_project, repo, arch, None, None)
        graph_dest_dir = os.path.join(graph_root_dir, repo, arch)
        if not os.path.exists(graph_dest_dir):
            os.makedirs(graph_dest_dir)
        filename = os.path.join(graph_root_dir, repo, arch, "builddepinfo.xml")
        with open(filename, 'w') as xml_file:
            xml_file.write(xml)

        set_obs_environment(os.getenv("OBS_API_URL"),
                            os.getenv("OBS_API_USERNAME"),
                            os.getenv("OBS_API_PASSWD"),
                            obs_project,
                            repo,
                            arch)

        make_dep_graph(filename, graph_dest_dir,
                       vis_dir, dep_graph_dir, template_filename,
                       packages_to_be_built)

    # sync to donwload server
    sync(sync_out_dir, sync_dest)

def create_build_dep_graph(build, obs_project, backenddb, content):

    sync_out_dir = os.path.join(os.getenv('WORKSPACE'),
                                    'dep_graph')

    sync_dest = os.path.join(os.getenv('PATH_REPO_BASE'),
                             content['repo_path'],
                             "builddata",
                             "depends")
    print "sync_dest = %s" % sync_dest

    template_filename="jenkins-scripts/common/dep_graph.html.template"
    graph_root_dir=os.path.join(sync_out_dir)
    os.makedirs(graph_root_dir)
    packages_to_be_built = []

    if re.match("^home:prerelease:", obs_project):
        info = build.get_info(obs_project)
        packages_to_be_built = info['packages']
        package_build_result = build.get_package_build_result(obs_project)
        #print package_build_result

    # copy vis and dep_graph dirs.
    jenkins_script_dir = os.path.join(os.getenv("WORKSPACE"), "jenkins-scripts")
    shutil.copytree(os.path.join(jenkins_script_dir,"vis"), os.path.join(graph_root_dir, "vis"))
    shutil.copytree(os.path.join(jenkins_script_dir,"dep_graph"), os.path.join(graph_root_dir, "dep_graph"))

    vis_dir="../../vis"
    dep_graph_dir="../../dep_graph"

    repo_status = build.get_repo_state(obs_project)
    for target_arch,status in repo_status.items():
        repo = target_arch.split("/")[0]
        arch = target_arch.split("/")[1]

        xml = build.get_dependson(obs_project, repo, arch, None, None)
        graph_dest_dir = os.path.join(graph_root_dir, repo, arch)
        if not os.path.exists(graph_dest_dir):
            os.makedirs(graph_dest_dir)
        filename = os.path.join(graph_root_dir, repo, arch, "builddepinfo.xml")
        with open(filename, 'w') as xml_file:
            xml_file.write(xml)

        if re.match("^home:prerelease:", obs_project):
            built_packages = []
            if repo not in package_build_result:
                continue
            if arch not in package_build_result[repo]:
                continue
            for package_name in package_build_result[repo][arch]:
                if package_build_result[repo][arch][package_name] == 'succeeded':
                    built_packages.append(package_name)

            print "packages_to_be_built: ", packages_to_be_built
            print "built_packages: ", built_packages
            make_dep_graph(filename, graph_dest_dir,
                           vis_dir, dep_graph_dir, template_filename,
                           packages_to_be_built, built_packages)
        else:
            make_dep_graph(filename, graph_dest_dir,
              vis_dir, dep_graph_dir, template_filename)

    # sync to download server
    dir_to_remove = os.path.join(sync_dest, "dep_graph")
    if os.path.exists(dir_to_remove):
        shutil.rmtree(dir_to_remove)
    sync(sync_out_dir, sync_dest)

def main():
    """Script entry point.
    """

    obs_api = os.getenv("OBS_API_URL")
    obs_user = os.getenv("OBS_API_USERNAME")
    obs_passwd = os.getenv("OBS_API_PASSWD")

    # Init backend database
    redis_host = os.getenv("REDIS_HOST")
    redis_port = int(os.getenv("REDIS_PORT"))
    backenddb = BackendDB(redis_host, redis_port)

    build = BuildService(obs_api, obs_user, obs_passwd)

    content = trigger_info(os.getenv("TRIGGER_INFO"))

    # action - prerelease_build_progress, prerelease, or postrelease
    action = content.get('action')

    obs_project = content.get("obs_project")
    obs_linked_project = content.get("obs_linked_project")

    if action == "prerelease_build_progress":
        create_build_progress_dep_graph_prerelease(build, obs_project, obs_linked_project, backenddb)
    elif action == "postrelease_build_progress":
        create_build_progress_dep_graph_post(build, obs_project, backenddb, content)
    elif action == "build_progress":
        create_build_progress_dep_graph(build, obs_project, content)
    elif action == "build_dep_graph":
        create_build_dep_graph(build, obs_project, backenddb, content)
    else:
        raise LocalError("Not supported action: %s" % action)

if __name__ == '__main__':
    try:
        sys.exit(main())
    except LocalError, err:
        print err
        sys.exit(1)
