#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4
#
# 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.
#
import os
import re
import sys
import time
import requests
import subprocess
import urlparse
from common.buildtrigger import trigger_info, trigger_next
import base64
import json

#from pprint import pprint


def x_le_y(x, y):
    pattern = r'tizen[0-9a-zA-Z_\-\.]*[0-9]{8}.([0-9]{1,2})'
    p = re.compile(pattern)
    x = int(p.search(x).group(1))
    y = int(p.search(y).group(1))
    return x <= y


def get_latest_snapshot_version(url, username='', password='', timeout=5):
    pattern = r'tizen[0-9a-zA-Z_\-\.]*[0-9]{8}.[0-9]{1,2}'
    p = re.compile(pattern)

    # get data from url
    for loop in range(10):
        try:
            f = requests.get(url,
                             auth=(username,
                                   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_latest_snapshot_version')
    else:
        raise Exception('can\'t get latest snapshot version')

    # return snapshot version
    return p.findall(f.text).pop()

def generate_links(url, ignores=[], username='', password='', timeout=5):
    """docstring for get_links"""

    # append / at the end of url
    if not url.endswith('/'):
        url += '/'

    print('Start {}'.format(url))
    status_code = 0
    for loop in range(10):
        try:
            resp = requests.get(url,
                                auth=(username, password),
                                timeout=timeout)
            status_code = resp.status_code
            if 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 generate_links')
    else:
        raise Exception('Http resp is {}'.format(status_code))

    links = []

    # regex pattern
    #pattern_links = 'alt=\"\[(TXT|DIR|   )]*\]\".*<a href=\"(.*)\">'
    pattern_links = '.*<a href=\"(.*)\">'
    p = re.compile(pattern_links)

    # find all links
    found_links = p.findall(resp.text)
    # retrieve dirs and append files at list
    for link in found_links:
        sys.stdout.flush()
        new_url = urlparse.urljoin(url, link)
        #print(new_url, link[-1], link[-3:-1])
        if link[-1] == '/' and link[-3:-1] != '..' and not [ignore for ignore in ignores if re.findall(ignore, link)]:
            links.extend(generate_links(new_url, ignores))
        elif link[-1] != '/' and not [ignore for ignore in ignores if re.findall(ignore, link)]:
            links.append(new_url)
    print('Done {}'.format(url))
    return links


def generate_aria2_input(filename, links):
    """docstring for generate_aria2_inputs"""
    pattern = 'tizen[0-9a-zA-Z_\-\.]*[0-9]{8}.[0-9]{1,2}.*/'
    p = re.compile(pattern)

    with open(filename, 'w') as f:
        for link in links:
            f.write('{}\n'.format(link))
            try:
                dirs = '  dir={}\n'.format(p.search(link).group(0)[:-1])
            except Exception as err:
                print 'Exception... %s not parsed...' % link
            f.write(dirs)

def remote_jenkins_build_job( url, username, password, jobname, token, data=None):
    """ remote jenkins build job"""
    print 'remote pbs jenkins job '
    if url and username and password and jobname:
        url = '%s/job/%s/buildWithParameters?token=%s' \
              %(url, jobname, token)
        try:
            resp = requests.post(url, params=data,
                                auth=(username, password)
                                )
            status_code = resp.status_code
            print status_code
        except requests.exceptions.Timeout as e:
            print(e)
        except requests.exceptions.ConnectionError as e:
            print(e)
        except Exception as e:
            print(e)
            raise Exception('exception')

def main():

    print('-----[JOB STARTED: sync_repo ]-----')

    content = trigger_info(os.getenv("TRIGGER_INFO"))
    # get envs
    dest_dir = content.get('dest_dir')
    snapshot_url = content.get('snapshot_url')
    snapshot_username = content.get('snapshot_username')
    snapshot_password = content.get('snapshot_password')
    snapshot_version = content.get('snapshot_version')
    start_delay = float(content.get('sync_repo_start_delay'))
    project = content.get('project')
    # rsync download
    origin_rsync_path = os.path.join(os.getenv('IMG_SYNC_DEST_BASE'), dest_dir, snapshot_version)

    # get latest version
    latest_snapshot_version = get_latest_snapshot_version(snapshot_url)
    # wait until the repo is published
    print('Wait {} min...............'.format(start_delay))
    time.sleep(start_delay * 60)

    print('-----[Start to sync ]-----')
    retry_count = 3
    backup_links = []
    while True:
        ignores = ['buildlogs/', 'source/', 'build.xml', '.*debugsource.*.rpm', 'https://www.tizen.org']
#        ignores = ['buildlogs/', 'source/', 'build.xml', '.*debugsource.*.rpm']
        aria_urls_output = 'aria2c_urls'
        aria_urls_input = urlparse.urljoin(snapshot_url,
                                           snapshot_version)

        # get all file links from url
        links = generate_links(aria_urls_input, ignores=ignores)
        links = list(set(links) - set(backup_links))

        print(links)
        print('-----[sync {}]-----'.format(retry_count))
        if not links:
            if retry_count == 0:
                print('retry_count is 0')
                break
            if not os.path.exists(os.path.join(os.getcwd(),'repo', snapshot_version,'images')):
                time.sleep(10 * 60)
                retry_count -= 1
                continue
            print 'not links ------ break'
            break

        generate_aria2_input(aria_urls_output, links)
        backup_links.extend(links)

        print(links)
        # make a working dir 'repo' and chdir
        subprocess.call('mkdir -p {}'.format(os.path.join(os.getenv('PATH_REPO_BASE'), dest_dir, snapshot_version)), shell=True)
        subprocess.call('mkdir -p repo', shell=True)
        os.chdir('repo')

        # run aria2c
        aria2c_script = 'aria2c -i ../{0}'.format(aria_urls_output)
        if snapshot_username != '' and snapshot_username is not None:
            aria2c_script += ' --http-user={0}'.format(snapshot_username)
        if snapshot_password != '' and snapshot_password is not None:
            aria2c_script += ' --http-passwd={0}'.format(snapshot_password)

        subprocess.call(aria2c_script, shell=True)

        if not os.path.exists(os.path.join(os.getcwd(),snapshot_version,'builddata')):
            os.makedirs(os.path.join(os.getcwd(),snapshot_version,'builddata'))

        # make latest link
        if x_le_y(latest_snapshot_version, snapshot_version) and not os.path.exists(os.path.abspath('latest')):
            subprocess.call('ln -sf {0} {1}'.format(snapshot_version, 'latest'),
                            shell=True)

        # change working dir
        os.chdir(os.pardir)

    # rsync download
    origin_rsync_path = os.path.join(os.getenv('IMG_SYNC_DEST_BASE'), dest_dir)

    src_dir = os.path.join(os.getenv('WORKSPACE'), 'repo')
    print('origin_rsync_path=%s' % origin_rsync_path)
    print('src_dir=%s' % src_dir)

    cmd = 'ls %s | grep -v latest | parallel -j 8 rsync --compress --stats --archive --recursive --hard-links --verbose %s/{} %s/' \
            % (src_dir, src_dir, origin_rsync_path)
    print(cmd)
    subprocess.call(cmd, shell=True)

    cmd = 'ls %s | parallel -j 8 rsync --compress --stats --archive --recursive --hard-links --verbose %s/{} %s/' \
            % (src_dir, src_dir, origin_rsync_path)
    print(cmd)
    subprocess.call(cmd, shell=True)

    if content.get('remote_sync',False):
        download_rsync_path = os.path.join(os.getenv('RSYNC_SNAPSHOT'), dest_dir)
        print('download_rsync_path=%s' % download_rsync_path)
        cmd = 'ls %s | grep -v latest | parallel -j 8 rsync --compress --stats --archive --recursive --hard-links --verbose %s/{} %s/' \
                % (src_dir, src_dir, download_rsync_path)
        print(cmd)
        subprocess.call(cmd, shell=True)

        cmd = 'ls %s | parallel -j 8 rsync  --compress --stats --archive --recursive --hard-links --verbose %s/{} %s/' \
                % (src_dir, src_dir, download_rsync_path)
        print(cmd)
        subprocess.call(cmd, shell=True)

    rootstrap_data = {"build_id": snapshot_version,
                      "project": project,
                      "infra": "PUBLIC"
                      }
    trigger_next("create-sdkrootstrap", rootstrap_data)

    if os.getenv("REF_REMOTE_CREATE_PRJ_OBS_ENABLE", "0") == "1":
        # trigger sync obs job
        syncobs_data = {
                        "project": project,
                        "repo_path": os.path.join(dest_dir,snapshot_version),
                        "build_id": snapshot_version
                       }
        trigger_next("REF_REMOTE_CREATE_PRJ_OBS", syncobs_data)

    # Update NUGET pacakges to server
    if os.getenv("NUGET_UPDATE_ENABLE","0") == "1":
        repo_path = os.path.join(src_dir, snapshot_version)
        repo_dirs = {}
        arch_dirs = {}
        for repo_dir in os.listdir(os.path.join( repo_path, "repos")):
            arch_dirs = {}
            arch_dirs["archs"] = [ arch_dir for arch_dir in \
                                   os.listdir(os.path.join(repo_path, "repos", repo_dir, "packages")) ]
            repo_dirs[repo_dir] = arch_dirs

        nuget_data = {"build_id": snapshot_version,
                      "project": project,
                      "repo": repo_dirs,
                      "repo_path": os.path.join( dest_dir, snapshot_version ),
                     }
        trigger_next("update-nuget", nuget_data)
    ####

if __name__ == '__main__':
    try:
        sys.exit(main())
    except Exception as e:
        print(e)
        sys.exit(1)

