#!/usr/bin/env python
# This is not meant to be called in a standalone fashion. 
# It is used by the main scripts to read the tool configuration.
import sys
import os.path
import json
import describeRelease
import tempfile
import subprocess
import getpass
import urlparse
import multi_facility_process_helper_client
import cacheConfig
import globals

"""
Software package types (appTypes) are a name and a couple of folders (releaseFolder and linkFolder) in the config file - facilities.cfg.
The releaseFolder points to where the releases for the software packages are kept.
The linkFolder points to the where the soft links that switch between releases are located.
In addition, there is some logic that differs based on whether an application is an IOC or not. 
IOC's have multiple instances and hence have another level of indirection.
"""
appTypes = {
    'HIOC': 'A hard IOC using a st.cmd',
    'SIOC': 'A soft IOC using a hashbang',
    'HLA': 'A High level application',
    'Tools': 'Scripts typically in the tools/scripts folder',
    'Matlab': 'Matlab applications',
    'PyDM': 'PyDM displays'
}

# Stores facilities user can access
properFacilities = []
properFacilityConfigs = []
# Use realpath to determine where the script is being called from.
# This should follow softlinks etc and get us to where the configuration information is stored
scriptFolder = os.path.dirname(os.path.realpath(__file__))

if cacheConfig.userConfigExists():
    facilityConfigFile = cacheConfig.getFacilityConfigFiles()['user']
else:
    facilityConfigFile = cacheConfig.getFacilityConfigFiles()['global']

if "CRAM_OVERRIDE_FACILITIES_CFG" in os.environ:
    if globals.verbose:
        print "Using facilities config file specified in environment"
    facilityConfigFile = os.environ["CRAM_OVERRIDE_FACILITIES_CFG"]

if globals.isunittests:
    facilityConfigFile = os.path.join(scriptFolder, 'facilities_test.cfg')
if not os.path.exists(facilityConfigFile):
    raise Exception('Unable to find facilities configuration', facilityConfigFile)
with open(facilityConfigFile, 'r') as facilityfp:
    facilityConfig = json.load(facilityfp)

if globals.isunittests:
    testFolder = os.path.join("/tmp")
    if "CRAM_TESTFOLDER" in os.environ:
        testFolder = os.environ["CRAM_TESTFOLDER"]
    for facility in facilityConfig:
        facility['ssh'] = getpass.getuser() + '@' + os.uname()[1]
        for appType in appTypes:
            facility[appType]['releaseFolder'] = facility[appType]['releaseFolder'].replace('${TESTFOLDER}', testFolder)
            facility[appType]['linkFolder'] = facility[appType]['linkFolder'].replace('${TESTFOLDER}', testFolder)
            if 'packageFolder' in facility[appType]:
                facility[appType]['packageFolder'] = facility[appType]['packageFolder'].replace('${TESTFOLDER}', testFolder)
    if globals.verbose:
        print "Test facility config", facilityConfig

facilityConfigDict = {}
for facility in facilityConfig:
    facilityConfigDict[facility['name']] = facility


def getDocURL():
    """Get the URL to the Sphinx documentation that is part of this distribution"""
    return urlparse.urljoin("file://", os.path.join(scriptFolder, "docs", "build", "html", "index.html"))


def getFacilityConfig():
    """Return the facility configuration that is stored in the same folder as the scripts"""
    return facilityConfig


def getConfigForFacility(facility):
    """Return the configuration for a facility given its name"""
    return facilityConfigDict[facility]


def getListOfFacilities():
    """Return the names of the facilities as a list"""
    return [x['name'] for x in facilityConfig]


def readPackageConfig(autoDescribeRelease=False):
    """Read the package configuration as specified in the .cram/packageinfo"""
    packageInfofile = os.path.join('.cram', 'packageinfo')

    if not os.path.exists(packageInfofile):
        if autoDescribeRelease:
            describeRelease.describeRelease()
        else:
            return {}
    with open(packageInfofile, 'r') as packageInfofp:
        packageInfo = json.load(packageInfofp)
        return packageInfo


def determinePackageInfoFromArgs(args):
    '''Determine the package info based on a combination of arguments and current directory.
    Command line arguments always override information from the packageinfo.
    This exits with an error message if we cannot determine the name and the type.
    '''
    packageInfo = readPackageConfig(autoDescribeRelease=False)
    if 'name' in args and args.name:
        packageInfo['name'] = args.name
    if 'type' in args and args.type:
        packageInfo['type'] = args.type
    if 'type' not in packageInfo or 'name' not in packageInfo:
        if globals.verbose:
            print "Name is " + packageInfo['name']
            print "Type is " + packageInfo['type']
        print "    Error --- cannot determine the name or type of the software package."
        print "    If you are not running cram in a folder that contains the release for your package, " \
              "please use the name and type arguments to specify the package information for your package."
        print "    For example, cram ls --name multi_facility_build --type Tools"
        sys.exit(1);
    return packageInfo


def determineLinkFolder(facility, name, type):
    '''Determine the folder that contains the IOCs/links that indicate version
    facility - name of facility
    name - name of software package
    type - type of software package'''
    return os.path.join(getConfigForFacility(facility)[type]['linkFolder'])


def determineReleaseFolder(facility, name, type):
    '''Determine the folder that contains the releases
	facility - name of facility
	name - name of software package
	type - type of software package'''
    return os.path.join(getConfigForFacility(facility)[type]['releaseFolder'])


def determineLinkPath(facility, name, type, ioc):
    '''Determine the link that needs to be switched for the given facility, ioc,
    application name and application type'''
    if type in ['SIOC', 'HIOC']:
        if ioc == 'ALL':
            return os.path.join(getConfigForFacility(facility)[type]['linkFolder'], name, "current")
        else:
            return os.path.join(getConfigForFacility(facility)[type]['linkFolder'], name, ioc,
                                "iocSpecificRelease")
    else:
        return os.path.join(getConfigForFacility(facility)[type]['linkFolder'], name)


def usesGateway(facility):
    try:
        gw = getConfigForFacility(facility)['gateway']
    except LookupError:
        return False

    if gw == "" or gw is None:
        return False
    return True
