#!/usr/bin/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 sys
from merge import QueueFile
import logging
import os
import os.path
import configure
import json

# first commandline argument should be the file to process
argc = len(sys.argv)
if argc != 2 and argc != 3:
    logging.error("Invalid usage, args passed: %s" % sys.argv)
    sys.exit(1)

# FIXME we should get this location from a configuration class
jsonPath = "/var/cache/cloud/%s"
jsonFilename = sys.argv[1]
jsonConfigFile = jsonPath % jsonFilename
currentGuestNetConfig = "/etc/cloudstack/guestnetwork.json"


def finish_config():
    # Converge
    returncode = configure.main(sys.argv)
    sys.exit(returncode)


def process_file():
    logging.info("Processing JSON file %s" % sys.argv[1])
    qf = QueueFile()
    if len(sys.argv) > 2 and sys.argv[2].lower() == "false":
        qf.keep = False

    qf.setFile(sys.argv[1])
    qf.load(None)
    # These can be safely deferred, dramatically speeding up loading times
    if not (os.environ.get('DEFER_CONFIG', False) and ('vm_dhcp_entry.json' in sys.argv[1] or 'vm_metadata.json' in sys.argv[1])):
        # Converge
        finish_config()


def is_guestnet_configured(guestnet_dict, keys):

    existing_keys = []
    new_eth_key = None

    for k1, v1 in guestnet_dict.iteritems():
        if k1 in keys and len(v1) > 0:
            existing_keys.append(k1)

    if not existing_keys:
        '''
        It seems all the interfaces have been removed. Let's allow a new configuration to come in.
        '''
        logging.warn("update_config.py :: Reconfiguring guest network...")
        return False

    file = open(jsonConfigFile)
    new_guestnet_dict = json.load(file)

    if not new_guestnet_dict['add']:
        '''
        Guest network has to be removed.
        '''
        logging.info("update_config.py :: Removing guest network...")
        return False

    '''
    Check if we have a new guest network ready to be setup
    '''
    device = new_guestnet_dict['device']

    if device in existing_keys:
        '''
        Device already configured, ignore.
        '''
        return True

    exists = False

    for key in existing_keys:
        for interface in guestnet_dict[key]:
            new_mac = new_guestnet_dict["mac_address"].encode('utf-8')
            old_mac = interface["mac_address"].encode('utf-8')
            new_ip = new_guestnet_dict["router_guest_ip"].encode('utf-8')
            old_ip = interface["router_guest_ip"].encode('utf-8')

            if (new_mac == old_mac) and (new_ip == old_ip):
                exists = True
                break

        if exists:
            break

    return exists


# If the command line json file is unprocessed process it
# This is important or, the control interfaces will get deleted!
if jsonFilename != "cmd_line.json" and os.path.isfile(jsonPath % "cmd_line.json"):
    qf = QueueFile()
    qf.setFile("cmd_line.json")
    qf.load(None)

if not (os.path.isfile(jsonConfigFile) and os.access(jsonConfigFile, os.R_OK)):
    # Ignore if file is already processed
    if os.path.isfile(jsonPath % ("processed/" + jsonFilename + ".gz")):
        sys.exit(0)
    logging.error("update_config.py :: Unable to read and access %s to process it" % jsonConfigFile)
    sys.exit(1)

# If the guest network is already configured and have the same IP, do not try to configure it again otherwise it will break
if jsonFilename.startswith("guest_network.json"):
    if os.path.isfile(currentGuestNetConfig):
        file = open(currentGuestNetConfig)
        guestnet_dict = json.load(file)

        if not is_guestnet_configured(guestnet_dict, ['eth1', 'eth2', 'eth3', 'eth4', 'eth5', 'eth6', 'eth7', 'eth8', 'eth9']):
            logging.info("update_config.py :: Processing Guest Network.")
            process_file()
        else:
            logging.info("update_config.py :: No need to process Guest Network.")
            finish_config()
    else:
        logging.info("update_config.py :: No GuestNetwork configured yet. Configuring first one now.")
        process_file()
else:
    logging.info("update_config.py :: Processing incoming file => %s" % sys.argv[1])
    process_file()
