/**
* Licensed Materials - Property of IBM* and/or HCL**
* IBM UrbanCode Deploy
* (c) Copyright IBM Corporation 2002, 2017. All Rights Reserved.
* (c) Copyright HCL Technologies Ltd. 2018. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*
* * Trademark of International Business Machines
* ** Trademark of HCL Technologies Limited
*/

package com.urbancode.air.plugin.f5

import iControl.Interfaces

public class F5Server {
    def props
    def serverUrlArray
    def serverHostAndPort
    def serverIp
    def long serverPort
    def username
    def password
    def interfaces
    def timeout
    def folder
    def version

    // Main constructor for the F5Server plugin. Gathers and parses general
    // input properties for establishing a connection to the F5 Server.
    // Sets the active partition
    public F5Server(Map<String,String> props) {
        this.props = props
        this.serverUrlArray = props['serverURL']?.split('://') as String[]
        this.serverHostAndPort = serverUrlArray[1]?.split(':') as String[]
        this.serverIp = serverHostAndPort[0]
        if (serverHostAndPort.length > 1) {
            //port specified
            this.serverPort = Long.parseLong(serverHostAndPort[1])
        }
        else if (serverUrlArray[0].toString().length() >= 5) {
            //https default
            println("No server port specifed.  Defaulting to 443")
            this.serverPort = Long.parseLong("443")
        }
        else {
            //http default
            println("No port specifed.  Defaulting to 80")
            this.serverPort = Long.parseLong("80")
        }

        this.username = props['username']
        this.password = props['password']

        if (props['timeout']) {
            this.timeout = Integer.parseInt(props['timeout'])
        } else {
            this.timeout = 10
        }

        setActiveFolder()
    }

    // Creates the connection between the F5 server and the plugin
    public Interfaces getConnection() {
        if (!interfaces){
            interfaces = new Interfaces()
            com.urbancode.air.XTrustProvider.install()
            println("Connecting to server $serverIp:$serverPort using timeout of $timeout second(s)")

            if (!interfaces.initialize(serverIp, serverPort, username, password))
                throw new Exception("Could not connect!")
        }
        return interfaces
    }

    // Retrieve the full version of the current F5 system. Trims it into an integer
    public int getMajorVersion() {
        if(!version) {
            def rawVersion = getConnection().getSystemSystemInfo().get_version()
            println "F5 version: $rawVersion"
            if (rawVersion && rawVersion.length() > 9) {
                rawVersion = rawVersion[0..(rawVersion.indexOf('.') - 1) ]
                version = Integer.parseInt(rawVersion.trim()[8..-1])
            }
            else {
                throw new Exception("Unknown version $rawVersion")
            }
        }

        return version
    }

    // Retrieves the partition name from the input properties and parses it into a useable format
    public String getFolderName() {
        if (!folder && props['partition']) {
            folder = props['partition'].trim().replaceAll('\\\\', '/')
            if (getMajorVersion() > 10) {
                if (!folder.startsWith('/')) {
                    folder = '/' + folder
                }
                while (folder[1] == '/') {
                    folder = folder[1..-1]
                }
                if (folder[-1] != '/') {
                    folder = folder + '/'
                }
            }
        }
        return folder
    }

    // Sets the active F5 partition to the location given by the input properties
    public void setActiveFolder() {
        if (getFolderName()) {
            if (getMajorVersion() > 10) {
                println "Setting current folder to ${getFolderName()}"
                getConnection().getSystemSession().set_active_folder(getFolderName())
            }
            else {
                println "Setting active partition to ${getFolderName()}"
                getConnection().getManagementPartition().set_active_partition(getFolderName())
            }
        }
    }


    // Retrieves a text block and parses it into a String array
    // Used for node names, node addresses, monitors, and iRule properties
    public String[] text2StringArray(String input) {
        def output
        if (input) {
            output = input.split('\n').join(',').split(',').findAll{
                it && it.trim().size() > 0} as String[]
            output = output.collect {it.trim().replaceAll("\\s","")}
        }

        return output
    }

    // Retrieves a text block and parses the text into Long array
    // Used for node connections and node ports properties
    public Long[] text2LongArray(String input) {
        def output = []
        if (input) {
            def tempStringArray = []
            tempStringArray = input.split('\n').join(',').split(',').findAll{
                it && it.trim().size() > 0} as String[]
            tempStringArray.each {it.trim().replaceAll("\\s","")}

            for (temp in tempStringArray){
                try {
                    output.add(Long.parseLong(temp.replaceAll("\\s","")))
                } catch (Exception ex) {
                    throw new Exception("You entered an invalid character in an Integer only field. Please ensure integers and commas are the only characters entered.")
                }
            }
        }

        return output
    }

    // F5 assumes the partition/folder name is at the beginning of each iRule and Data Group
    // This method will ensure that this is true for all iRules and Data Groups given
    public String[] appendFolderNames(String ... rules) {
        def newRule = []
        for (rule in rules) {
            if (!rule.startsWith(getFolderName())) {
                newRule << getFolderName() + rule
            }
            else {
                newRule << rule
            }
        }
        return newRule
    }
}
