#!/usr/bin/env python
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Intel, Inc.
#
#    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.
#
"""A Gerrit related operations wrapper"""

import getpass
import os
import sys
import json

from subprocess import Popen, PIPE

def is_ref_deleted(oldrev, newrev):
    """Check if ref is deleted in Gerrit using old and new refs from
       'ref updated' Gerrit event.
    """
    # 0000*0 is a special git hash code in gerrit for deleted git object
    return oldrev != newrev and newrev == '0' * 40

class GerritError(Exception):
    """Handle with local Gerrit Error"""
    pass

class Gerrit:
    """ Gerrit ssh client command line warper """
    def __init__(self, host, username=getpass.getuser(), port=29418,
                 silent_mode=False):

        self.host = host
        self.username = username
        self.port = port
        self.silent_mode = silent_mode

        # Check connection
        self._cmd_run('version')

    def _cmd_run(self, cmd, args=()):
        """
        A cmd running wrapper.
        Return: std output
        Raises: GerritError if return code is not 0.
        """

        cmd = "ssh -p %s %s@%s gerrit %s %s" % (self.port, self.username,
                                                self.host, cmd, ' '.join(args))
        pobj = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
        rcode = pobj.wait()
        if rcode:
            raise GerritError("Error running %s. Return code: %d, error: %s" % \
                              (cmd, rcode, pobj.stderr.read()))
        return pobj.stdout.readlines()

    def query(self, query):
        """Execute Gerrit query operation"""

        ret_list = []

        if type(query) != list:
            query = [query]
        query.append('--format JSON')
        results = self._cmd_run('query', query)

        for json_str in results:
            item = json.loads(json_str)
            if item.get('type') != 'stats':
                ret_list.append(item)

        return ret_list

    def ls_projects(self, args=()):
        """List Gerrit projects"""

        ret_list = []

        #results = self._cmd_run('ls-projects', args)

        sys.stdin, out = os.popen2("ssh -p %s %s@%s 'gerrit ls-projects %s'"
                                   %(self.port, self.username, self.host,
                                     ' '.join(args)))
        for prj in out.readlines():
            ret_list.append(prj.strip())

        return ret_list

    def create_project(self, project, *keys):
        """Create Gerrit project"""

        args = [project] + list(keys)

        self._cmd_run('create-project', args)

    def review(self, commit=None, project=None, change_id_set=None,
               message='', verified=0, codereview=0, submit=False):
        """A wrapper method used to execute gerrit review operation"""

        args = []

        if project:
            args.append('--project %s ' % project)

        if message:
            args.append('--message \'"%s"\'' % \
                    message.replace('"', '\\"').replace("'", ""))

        if verified:
            args.append('--verified %s ' % verified)

        if codereview:
            args.append('--code-review %s ' % codereview)

        if submit:
            args.append('--submit ')

        if commit or change_id_set:
            if commit:
                args.append('%s' % commit)
            elif change_id_set:
                args.append('%s' % change_id_set)
        else:
            raise GerritError('Error: either commit or changeid, patchset is needed')

        if not self.silent_mode:
            self._cmd_run('review', args)

    def ls_groups(self, args=[]):
        """List Groups"""

        results = self._cmd_run('ls-groups', args)

        return map(lambda t: t.strip(), results)

    def ls_members(self, args=[]):
        """List Members"""

        results = self._cmd_run('ls-members', args)

        return map(lambda t: t.strip(), results)[1:]

def get_gerrit_event(env_switch=None):
    """ get gerrit event info from environment parameters """
    event = {}

    for element in os.environ.keys():
        if element.startswith('GERRIT_'):
            event[element[len('GERRIT_'):].lower()] = os.getenv(element)

    if env_switch:
        for element in os.environ.keys():
            if element.startswith(env_switch+'GERRIT_'):
                event[element[len(env_switch+'GERRIT_'):].lower()] = os.getenv(element)

    print '\nGerrit Event:\n', json.dumps(event, indent=4)
    return event

class GerritEnv(object):

    def __init__(self, env_switch=None):

        self.host     = os.getenv(env_switch+'GERRIT_HOST')
        self.hostname = os.getenv(env_switch+'GERRIT_HOSTNAME')
        self.username = os.getenv(env_switch+'GERRIT_USERNAME')
        self.sshport  = os.getenv(env_switch+'GERRIT_SSHPORT')
        self.gitcache = os.getenv(env_switch+'GIT_CACHE_DIR')

