#!/usr/bin/python
#
# Copyright (c) 2008--2012 Red Hat, Inc.
#
# Authors: Pradeep Kilambi
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
#
#

import sys
import os

from optparse import Option, OptionParser
from spacewalk.common.rhnLog import initLOG, log_debug
from spacewalk.common.rhnConfig import CFG, initCFG
from spacewalk.common import rhn_rpm
from spacewalk.server import rhnSQL
from spacewalk.server.rhnServer import server_packages
from spacewalk.satellite_tools.progress_bar import ProgressBar

initCFG('server.satellite')
initLOG(CFG.LOG_FILE, CFG.DEBUG)

OPTIONS = None
debug = 0
verbose = 0

options_table = [
    Option("-v", "--verbose",       action="store_true",
        help="Increase verbosity"),
    Option(   "--debug",            action="store",
        help="logs the debug information to a log file"),
    Option(    "--clean-possible-wrong", action="store_true",
        help="clean possible wrong calculated keyids"),
]


def main():
    global options_table, debug, verbose, clean_wrong
    parser = OptionParser(option_list=options_table)

    (options, args) = parser.parse_args()

    if args:
        for arg in args:
            sys.stderr.write("Not a valid option ('%s'), try --help\n" % arg)
        sys.exit(-1)

    if options.verbose:
        initLOG(CFG.LOG_FILE, 1)
        verbose = 1

    if options.debug:
        initLOG(CFG.LOG_FILE, options.debug or 1)
        debug = 1

    rhnSQL.initDB()

    if options.clean_possible_wrong:
        clean_wrong()

    process_package_data()



_get_needed_pkgs_query = """
select P.id, P.path, CV.checksum_type, CV.checksum
  from rhnPackage P
       left join rhnPackageKeyAssociation PA on PA.package_id = P.id
      inner join rhnChecksumView CV on CV.id = P.checksum_id
      inner join rhnPackageKey pk on pa.key_id = pk.id
       left join rhnPackageProvider pp on pk.provider_id = pp.id
 where (PA.key_id is null
        and P.rpm_version is not null)
    or (P.org_id is NULL and pp.name is NULL)
"""

_get_possible_wrong_query = """
   select X.key_id from (
       select pa.key_id, count(pa.key_id) keycount, pk.provider_id
         from rhnpackagekeyassociation pa
         join rhnpackagekey pk on pk.id = pa.key_id
        where pk.provider_id is null
     group by pa.key_id, pk.provider_id
     order by keycount DESC
   ) X
   where X.keycount < 20
"""

_delete_key_association_query = """
  delete from rhnpackagekeyassociation
   where key_id = :id
"""

_delete_key_association_by_pkgid_query = """
  delete from rhnpackagekeyassociation
   where package_id = :id
"""

_delete_key_query = """
  delete from rhnpackagekey
   where id = :id
"""

def clean_wrong():
    query = rhnSQL.prepare(_get_possible_wrong_query)

    query.execute()
    keyids = query.fetchall_dict()

    if not keyids:
        # no possible wrong keyids found
        return

    del_keyass_query = rhnSQL.prepare(_delete_key_association_query)
    del_key_query = rhnSQL.prepare(_delete_key_query)
    if verbose: print "Processing %s possible wrong keyids" % len(keyids)
    i = 0
    for K in keyids:
        del_keyass_query.execute(id=K['key_id'])
        del_key_query.execute(id=K['key_id'])
        i = i + 1
        # we need to break the transaction to smaller pieces
        if i % 1000 == 0:
            rhnSQL.commit()

    rhnSQL.commit()
    return

def process_package_data():
    global verbose, debug

    _get_path_sql = rhnSQL.prepare(_get_needed_pkgs_query)

    _get_path_sql.execute()
    pkgs = _get_path_sql.fetchall_dict()

    if not pkgs:
        # Nothing to change
        return
    if verbose: print "Processing %s packages" % len(pkgs)
    pb = ProgressBar(prompt='standby: ', endTag=' - Complete!', \
                     finalSize=len(pkgs), finalBarLength=40, stream=sys.stdout)
    pb.printAll(1)
    skip_list = []
    i = 0
    for pkg in pkgs:
        pb.addTo(1)
        pb.printIncrement()
        path =  pkg['path']

        if path is None:
                continue
        full_path = os.path.join(CFG.MOUNT_POINT, path)
        checksum_type = pkg['checksum_type']
        checksum = pkg['checksum']

        if not os.path.exists(full_path):
            skip_list.append(full_path)
            if debug:
                log_debug(1, "File not %s found" % (full_path))
            continue

        try:
            hdr = rhn_rpm.get_package_header(filename=full_path)
        except:
            rhnSQL.commit()
            raise

        # delete possible wrong association
        del_keyass_query = rhnSQL.prepare(_delete_key_association_by_pkgid_query)
        del_keyass_query.execute(id=pkg['id'])

        # Process gpg key ids
        server_packages.processPackageKeyAssociations(hdr, checksum_type, checksum)
        if debug:
            log_debug(1, "gpg key info updated from %s" % full_path )
        i = i + 1
        # we need to break the transaction to smaller pieces
        if i % 1000 == 0:
            rhnSQL.commit()
    pb.printComplete()
    # All done, final commit
    rhnSQL.commit()
    sys.stderr.write("Transaction Committed! \n")
    if verbose:
        print " Skipping %s packages, paths not found" % len(skip_list)
    return


if __name__ == '__main__':
    main()
