#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import optparse
import copy
import os
import re
import sys
import errno

# The global prefix and current directory
root = "/usr/odp"
current = root + "/current"
vconfroot='/etc'
packages = ( "accumulo", "atlas", "flume", "falcon", "hadoop",
             "hbase", "hive", "hive-hcatalog",
             "kafka", "kafka3", "knox", "mahout", "oozie", "ozone",
             "pig", "ranger-admin", "flink",
             "ranger-kms", "ranger-usersync", "ranger-tagsync",
             "slider", "spark", "spark2","spark3", "spark-rapids", "sqoop", "storm",
             "storm-slider-client",
             "tez", "livy2","livy3","livy3_3_3_3","livy3_3_5_1","zookeeper", "zeppelin",
             "hive2", "tez_hive2", "druid", "superset",
             "hive_warehouse_connector", "spark_schema_registry","registry",
             "nifi","nifi-registry","airflow","cruise-control","cruise-control3",
             "impala","hue","kudu","trino","pinot","clickhouse")

def printHelp():
    print("""
usage: conf-select [-h] [<command>] package --stack-version --conf-version
arguments:
  <command>          One of create-conf-dir, set-conf-dir
  <--package>        package name to set
  <--stack-version>  stack version number
  <--conf-version>   conf version to set
optional arguments:
  -h, --help  show this help message and exit
Commands:
  set-conf-dir      : set the conf to a specified version
  create-conf-dir   : create the specified conf directory
  dry-run-set       : dry run for set conf
  dry-run-create    : dry run for create conf
""")

def chkPkg(sver, pname):
    '''checks package name against the package tuple,
    check if the package directory exists and returns True
    '''
    pkgdir = os.path.join(root,sver,pname)
    if not os.path.isdir(pkgdir) or pname not in packages:
        print(pname +" not installed or incorrect package name")
        sys.exit(1)
    return True


def chksVer(sver):
    '''returns True if the stack version number
    exists'''
    if not os.path.isdir(os.path.join(root,sver)):
        print (sver +" Incorrect stack version")
        sys.exit(1)
    return True


def chkPath(pname, sver, cver, method):
    confpath = os.path.join(vconfroot,pname,sver,cver)
    if method == "create" and os.path.exists(confpath):
        print (confpath+" exist already")
        sys.exit(1)
    if method == "set" and not os.path.exists(confpath):
        print (confpath+" does not exist")
        sys.exit(1)
    return True


def check(sver, pname, cver, method):
    '''Aggregates chksVer, chkPkg and checks if path exits.
    Returns True if all the conditions are met'''
    chksVer(sver)
    chkPkg(sver, pname)
    chkPath(pname, sver, cver, method)


def drcrtConfDir(pname, sver, cver):
    chksVer(sver)
    chkPkg(sver, pname)
    for confmapkey,confmapval in confmap.items():
        path = os.path.join(vconfroot,confmapkey,sver,cver)
        print(path)


def crtConfDir(pname, sver, cver):
    path = os.path.join(vconfroot,pname,sver,cver)
    check(sver, pname, cver, "create")
    for confmapkey,confmapval in confmap.items():
        path = os.path.join(vconfroot,confmapkey,sver,cver)
        try:
            os.makedirs(path)
            print(path)
        except OSError as exc:
            if exc.errno == errno.EACCES:
                print ("Permission denied")


def drsetConfDir(pname, sver):
    chksVer(sver)
    chkPkg(sver, pname)
    for confmapkey,confmapval in confmap.items():
        confdir = os.path.join(root,sver,pname,confmapval)
        if os.path.exists(confdir) and os.path.islink(confdir):
            print(confdir)
        else:
            print(confdir+" does not exist")
            sys.exit(1)


def setConfDir(pname, sver, cver):
    check(sver, pname, cver, "set")
    for confmapkey,confmapval in confmap.items():
        path = os.path.join(vconfroot,confmapkey,sver,cver)
        confdir = os.path.join(root,sver,pname,confmapval)

        if os.path.exists(confdir) and not os.path.islink(confdir):
            raise Exception("Expected confdir %s to be a symlink." % confdir)

        if os.path.islink(confdir) and not os.path.exists(confdir):
            os.remove(confdir)

        if os.path.exists(confdir):
            if path == os.readlink(confdir):
                return
            else:
                os.remove(confdir)

        os.symlink(path, confdir)
        print(confdir + " -> " + path)


# Start of main
parser = optparse.OptionParser(add_help_option=False)
parser.add_option("-h", "--help", action="store_true", dest="help",
                  help="print help")
parser.add_option("-p", "--package", action="store", dest="pname",
                  help="package name")
parser.add_option("-s", "--stack-version", action="store", dest="sver",
                  help="stack verison number")
parser.add_option("-c", "--conf-version", action="store", dest="cver",
                  help="conf verison number", default = '0' )

(options, args) = parser.parse_args()
'''default conf mapping'''
confmap = {options.pname : "conf"}
'''conf mapping if the pkg name is hive-hcatalog'''
if options.pname == "hive-hcatalog":
    confmap = {"hive-hcatalog":"etc/hcatalog",
               "hive-webhcat":"etc/webhcat"}

if options.help or len(args) == 0:
    printHelp()
elif not options.pname or not options.sver:
    parser.error("Invalid option")
    printHelp()
elif args[0] == 'create-conf-dir':
    crtConfDir(options.pname, options.sver, options.cver)
elif args[0] == 'set-conf-dir':
    setConfDir(options.pname, options.sver, options.cver)
elif args[0] == 'dry-run-set':
    drsetConfDir(options.pname, options.sver)
elif args[0] == 'dry-run-create':
    drcrtConfDir(options.pname, options.sver, options.cver)
else:
    printHelp()
