#!/usr/bin/python2
#
# Copyright (C) 2016 ScyllaDB
#

#
# This file is part of Scylla.
#
# Scylla is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import print_function

import argparse
import json
import urllib
import urllib2
import requests
import ConfigParser
import os
import sys
import subprocess
import uuid
import re
import glob
from pkg_resources import parse_version

VERSION = "1.0"
quiet = False
# Temporary url for the review
version_url = "https://i6a5h9l1kl.execute-api.us-east-1.amazonaws.com/prod/check_version"

def trace(*vals):
    print(''.join(vals))

def traceln(*vals):
    trace(*(vals + ('\n',)))

def help(args):
    parser.print_help()

def sh_command(*args):
    p = subprocess.Popen(args, stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
    out, err = p.communicate()
    if err:
        raise Exception(err)
    return out

def get_json_from_url(path):
    data = sh_command("curl", "-s", "-X", "GET", path)
    return json.loads(data)

def get_api(path):
    return get_json_from_url("http://" + api_address + path)

def version_compare(a, b):
    return parse_version(a) < parse_version(b)

def create_uuid_file(fl):
    with open(args.uuid_file, 'w') as myfile:
        myfile.write(str(uuid.uuid1()) + "\n")

def sanitize_version(version):
    """
    Newer setuptools don't like dashed version strings, trim it to avoid
    false negative version_compare() checks.
    """
    if version and '-' in version:
        return version.split('-', 1)[0]
    else:
        return version

def get_repo_file(dir):
    files = glob.glob(dir)
    files.sort(key=os.path.getmtime, reverse=True)
    for name in files:
        with open(name, 'r') as myfile:
            for line in myfile:
                match = re.search(".*http.?://repositories.*/scylladb/([^/\s]+)/.*/([^/\s]+)/scylladb-.*", line)
                if match:
                    return match.group(2), match.group(1)
    return None, None

def check_version(ar):
    if config and (not config.has_option("housekeeping", "check-version") or not config.getboolean("housekeeping", "check-version")):
        return
    if ar.version and ar.version != '':
        current_version = sanitize_version(ar.version)
    else:
        current_version = sanitize_version(get_api('/storage_service/scylla_release_version'))
        if current_version == "":
            # API is down, nothing to do
            return
    try:
        params = "?version=" + current_version
        if ar.mode:
            # mode would accept any string.
            # use i for install, c (default) for running from the command line
            params = params + "&sts=" + ar.mode
        if uid:
            params = params + "&uu=" + uid
        if repo_id:
            params = params + "&rid=" + repo_id
        if repo_type:
            params = params + "&rtype=" + repo_type
        versions = get_json_from_url(version_url + params)
        latest_version = versions["version"]
        latest_patch_version = versions["latest_patch_version"]
    except:
        traceln("Unable to retrieve version information")
        return

    if latest_patch_version != latest_version:
        # user is using an older minor version
        if version_compare(current_version, latest_patch_version):
            # user is also running an older patch version
            traceln("Your current Scylla release is " + current_version + ", while the latest patch release is " + latest_patch_version +
                    ", and the latest minor release is " + latest_version + " (recommended)")
        else:
            traceln("You current Scylla release is ", current_version, " the latest minor release is ", latest_version, " go to http://www.scylladb.com for upgrade instructions")
    elif version_compare(current_version, latest_patch_version):
            traceln("You current Scylla release is ", current_version, " while the latest patch release is ", latest_patch_version, ", update for the latest bug fixes and improvements")

parser = argparse.ArgumentParser(description='ScyllaDB help report tool', conflict_handler="resolve")
parser.add_argument('-q', '--quiet', action='store_true', default=False, help='Quiet mode')
parser.add_argument('-c', '--config', default="", help='An optional config file. Specifying a missing file will terminate the script')
parser.add_argument('--uuid', default="", help='A uuid for the requests')
parser.add_argument('--uuid-file', default="", help='A uuid file for the requests')
parser.add_argument('--repo-files', default="", help='The repository files that is been used for private repositories')
parser.add_argument('--api-address', default="localhost:10000", help='The ip and port of the scylla api')

subparsers = parser.add_subparsers(help='Available commands')
parser_help = subparsers.add_parser('help', help='Display help information')
parser_help.set_defaults(func=help)
parser_system = subparsers.add_parser('version', help='Check if the current running version is the latest one')
parser_system.add_argument('--mode', default="c", help='Which mode the version check runs')
parser_system.add_argument('--version', default="", help='Use a given version to compare to')
parser_system.set_defaults(func=check_version)

args = parser.parse_args()
quiet = args.quiet
config = None
repo_id = None
repo_type = None

if args.config != "":
    if not os.path.isfile(args.config):
        traceln("Config file ", args.config, " is missing, terminating")
        sys.exit(0)
    config = ConfigParser.SafeConfigParser()
    config.read(args.config)
uid = None
if args.uuid != "":
    uid = args.uuid
if args.uuid_file != "":
    if not os.path.exists(args.uuid_file):
        create_uuid_file(args.uuid_file)
    with open(args.uuid_file, 'r') as myfile:
        uid = myfile.read().replace('\n', '')
api_address = args.api_address
if args.repo_files != "":
    repo_type, repo_id = get_repo_file(args.repo_files)
args.func(args)
