#!/usr/bin/env python
import os
import sys
import argparse
import subprocess
import globals
import toolconfig
import multi_facility_process_helper_client
import sets
from globals import UserParamsException


def listCurrentReleases(args):
    """List the releases that are currently deployed in all the facilities for the given application.
    All the work happens in determineIOCVersions and determineHLAVersion in multi_facility_process_helper.py
    This is just formatting.
    """
    packageInfo = toolconfig.determinePackageInfoFromArgs(args)
    for facility in toolconfig.getListOfFacilities():
        arg = {}
        arg['name'] = packageInfo['name']
        arg['releaseFolder'] = toolconfig.determineReleaseFolder(facility, packageInfo['name'], packageInfo['type'])
        arg['linkFolder'] = toolconfig.determineLinkFolder(facility, packageInfo['name'], packageInfo['type'])
        if packageInfo['type'] in ['SIOC', 'HIOC']:
            commandsAndArgs = []
            commandsAndArgs.append(('determineIOCVersions', arg))
            results = multi_facility_process_helper_client.executeCommandsOnFacility(facility, commandsAndArgs)
            iocVersionResult = results[0]
            if globals.verbose:
                print "After remote execution, results is ", iocVersionResult
            print "Current versions on facility:\033[1;31m", facility, "\033[0m"
            if not 'master' in iocVersionResult:
                # Facility does not have a iocTop folder for this package
                continue;
            masterRelease = iocVersionResult['master']
            print "Current master release =>", masterRelease
            for ioc in iocVersionResult['iocs']:
                print "IOC:",  ioc['ioc'], "=>", ioc['release'], "(*)" if not ioc['isMaster'] else ""                    
        else:
            commandsAndArgs = []
            commandsAndArgs.append(('determineHLAVersion', arg))
            results = multi_facility_process_helper_client.executeCommandsOnFacility(facility, commandsAndArgs)
            hlaVersionResult = results[0]
            if globals.verbose:
                print "After remote execution, results is ", hlaVersionResult
            print "Current version on facility:\033[1;31m", facility, "\033[0m =>", hlaVersionResult 

def listAvailableReleases(args):
    """List the releases that are currently available. All we are doing here is an ls in the release folder"""
    packageInfo = toolconfig.determinePackageInfoFromArgs(args)
    availableReleases = {}
    for facility in toolconfig.getListOfFacilities():
        commandsAndArgs = []
        releaseFolder = os.path.join(toolconfig.determineReleaseFolder(facility, packageInfo['name'], packageInfo['type']),  packageInfo['name'])
        commandsAndArgs.append(('ls', [releaseFolder]))
        results = multi_facility_process_helper_client.executeCommandsOnFacility(facility, commandsAndArgs)
        paths = results[0]
        if globals.verbose:
            print "After remote execution, results is ", paths
        for path in paths:
            if path['isFolder'] and not path['isLink']:
                 if path['name'] in availableReleases:
                     availableReleases[path['name']].append(facility)
                 else:
                     availableReleases[path['name']] = [facility]
    for release in sorted(availableReleases.keys()):
        facilitiesWithRelease = availableReleases[release]
        if facilitiesWithRelease == toolconfig.getListOfFacilities():
            print release
        else:
            print release, " - avail only on ", ",".join(facilitiesWithRelease)

def listIOCSpecificReleases(args):
    '''List IOCs and their releases that point to a release other than the master release.
    Very similar to listCurrentReleases - changes are to only list IOCS which point to something other than the current release'''
    packageInfo = toolconfig.determinePackageInfoFromArgs(args)
    for facility in toolconfig.getListOfFacilities():
        arg = {}
        arg['name'] = packageInfo['name']
        arg['releaseFolder'] = toolconfig.determineReleaseFolder(facility, packageInfo['name'], packageInfo['type'])
        arg['linkFolder'] = toolconfig.determineLinkFolder(facility, packageInfo['name'], packageInfo['type'])
        if packageInfo['type'] in ['SIOC', 'HIOC']:
            commandsAndArgs = []
            commandsAndArgs.append(('determineIOCVersions', arg))
            results = multi_facility_process_helper_client.executeCommandsOnFacility(facility, commandsAndArgs)
            iocVersionResult = results[0]
            if globals.verbose:
                print "After remote execution, results is ", iocVersionResult
            if not iocVersionResult:
                print "Package {0} does not seem to be in facility {1}".format(packageInfo['name'], facility)
                continue
            print "IOC specific versions on facility:\033[1;31m", facility, "\033[0m"
            masterRelease = iocVersionResult['master']
            print "Current master release =>", masterRelease
            for ioc in iocVersionResult['iocs']:
                if not ioc['isMaster']:
                    print "IOC:",  ioc['ioc'], "=>", ioc['release'], "(*)" if not ioc['isMaster'] else ""                    
        else:
            print "IOC specific releases do not apply to software packages of type",  packageInfo['type']

def determineUnusedReleases(name, type):
    '''Determine the list of releases that are unused'''
    usedReleases = sets.Set()
    availableReleases = sets.Set()
    for facility in toolconfig.getListOfFacilities():
        arg = {}
        arg['name'] = name
        arg['releaseFolder'] = toolconfig.determineReleaseFolder(facility, name, type)
        arg['linkFolder'] = toolconfig.determineLinkFolder(facility, name, type)
        commandsAndArgs = []
        commandsAndArgs.append(('determineIOCVersions', arg) if type in ['SIOC', 'HIOC'] else ('determineHLAVersion', arg))
        releaseFolder = os.path.join(toolconfig.determineReleaseFolder(facility, name, type),  name)
        commandsAndArgs.append(('ls', [releaseFolder]))
        results = multi_facility_process_helper_client.executeCommandsOnFacility(facility, commandsAndArgs)
        versionResult = results[0]
        if globals.verbose:
            print "After remote execution, version results is ", versionResult
        if not versionResult:
            print "Package {0} does not seem to be in facility {1}".format(name, facility)
            continue
        usedReleases.add(versionResult['master'] if type in ['SIOC', 'HIOC'] else versionResult)
        if type in ['SIOC', 'HIOC']:
            for ioc in versionResult['iocs']:
                if not ioc['isMaster']:
                    usedReleases.add(ioc['release'])                    
        if globals.verbose:
            print "Used releases ", usedReleases
        # Let's compute the available releases
        paths = results[1]
        if globals.verbose:
            print "After remote execution, available releases paths is ", paths
        for path in paths:
            if path['isFolder'] and not path['isLink']:
                availableReleases.add(path['name'])
        if globals.verbose:
            print "All available releases", availableReleases
    unusedReleases = availableReleases.difference(usedReleases)
    return unusedReleases

def listUnusedReleases(args):
    ''' List unused releases. This is a combination of listCurrentReleases and listAvailableReleases. 
    We gather the releases available on all sites and the releases used on all sites.
    Unused releases is the set difference between these. 
    ''' 
    packageInfo = toolconfig.determinePackageInfoFromArgs(args)
    unusedReleases = determineUnusedReleases(packageInfo['name'], packageInfo['type'])
    if unusedReleases:
        print "Releases that are not currently being used"
        for release in unusedReleases:
            print "-->", release
    else:
        print "All available releases are being used"

def listRunningReleases(args):
    """List the releases that are currently deployed and running. Note this applies only for IOC applications. 
    """
    packageInfo = toolconfig.determinePackageInfoFromArgs(args)
    if packageInfo['type'] not in ['SIOC', 'HIOC']:
        print "Running releases can be listed only for IOC applications"
        return
    for facility in toolconfig.getListOfFacilities():
        arg = {}
        arg['name'] = packageInfo['name']
        arg['releaseFolder'] = toolconfig.determineReleaseFolder(facility, packageInfo['name'], packageInfo['type'])
        arg['linkFolder'] = toolconfig.determineLinkFolder(facility, packageInfo['name'], packageInfo['type'])
        arg['timeout'] = 1
        if packageInfo['type'] in ['SIOC', 'HIOC']:
            commandsAndArgs = []
            commandsAndArgs.append(('determineIOCVersions', arg))
            commandsAndArgs.append(('determineIOCRunningVersions', arg))
            results = multi_facility_process_helper_client.executeCommandsOnFacility(facility, commandsAndArgs)
            iocVersionResult = results[0]
            iocRunningResult = results[1]
            if globals.verbose:
                print "After remote execution, results is ", iocVersionResult
                print "After remote execution, running results is ", iocRunningResult
            print "Current versions on facility:\033[1;31m", facility, "\033[0m"
            if not 'master' in iocVersionResult:
                # Facility does not have a iocTop folder for this package
                continue;
            masterRelease = iocVersionResult['master']
            print "Current master release =>", masterRelease
            for ioc in iocVersionResult['iocs']:
                print "IOC:",  ioc['ioc'], "=>", ioc['release'], "(*)" if not ioc['isMaster'] else "", "=}", iocRunningResult[ioc['ioc']] if ioc['ioc'] in iocRunningResult else "N/A"                     

            
def execute(args):
    parser = argparse.ArgumentParser(prog="cram ls")
    parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose logging')
    parser.add_argument('-n', '--name', help='Specify the application name; we automatically pick this up from the package info if we are running this command in the folder containing the release')
    parser.add_argument('-t', '--type', help='Specifies the type of application from the deployment perspective. Possible values are ' + ", ".join(toolconfig.appTypes.keys()))
    parser.add_argument('-p', '--pushed', action='store_true', help='Show releases that are have been pushed/submitted and are available for this software package.')
    parser.add_argument('-u', '--unused', action='store_true', help='Show releases that are not being used currently.')
    parser.add_argument('-i', '--iocspecific', action='store_true', help='For IOC software packages, show IOCs and their releases that are different from the master release for this software package.')
    parser.add_argument('-r', '--running', action='store_true', help='For IOC software packages, also show the versions currently running on the IOC.')
    
    args = parser.parse_args(args)
    globals.verbose = args.verbose
    try:
        if args.pushed:
            listAvailableReleases(args)
        elif args.iocspecific:
            listIOCSpecificReleases(args)
        elif args.unused:
            listUnusedReleases(args)
        elif args.running:
            listRunningReleases(args)
        else:
            listCurrentReleases(args)
    except UserParamsException as upe:
        if not globals.verbose and not globals.isunittests:
            print upe
            sys.exit(-1)
        else:
            raise
            

if __name__ == "__main__":
    execute(sys.argv[1:])
