#!{{ python_executable }}
configuration_location = "{{ configuration_location }}"
promise_runner_path = "{{ promise_runner_path }}"
public_folder = "{{ public_folder }}"
promise_folder = "{{ promise_folder }}"

import sys
import os
import subprocess
import threading
import json
import ConfigParser


def main():
  # initialisation
  config = loadConfig([configuration_location])
  # search for configurations in monitor.conf.d
  configuration_folder_location = configuration_location + ".d"
  service_config_list = [
    loadConfig(os.path.join(configuration_folder_location, filename))
    for filename in os.listdir(configuration_folder_location)
    if os.path.isfile(os.path.join(configuration_folder_location, filename))
  ]
  # fill dict of service
  service_config_dict = {}
  for service_config in service_config_list:
    service_config_dict[service_config.get("service", "name")] = service_config
  # search for promises and make relation between service_config_list
  for filename in os.listdir(promise_folder):
    promise_path = os.path.join(promise_folder, filename)
    if os.path.isfile(promise_path) and os.access(promise_path, os.X_OK):
      service_name = filename
      service_config = service_config_dict.get(service_name)
      if service_name not in service_config_dict or softConfigGet(service_config, "service", "promise-path"):
        service_name = newServiceName(service_name, service_config_dict)
        service_config = ConfigParser.ConfigParser()
        service_config_list.append(service_config)
        service_config_dict[service_name] = service_config
        service_config.add_section("service")
        service_config.set("service", "name", service_name)
        service_config.set("service", "frequency", "* * * * *")  # every minutes
      service_config.set("service", "promise-path", promise_path)
  # filter services without promise-path
  service_config_dict = None
  service_config_list = [
    service_config
    for service_config in service_config_list
    if softConfigGet(service_config, "service", "promise-path")
  ]
  # generate monitor.json
  monitor_dict = {}
  tmp = softConfigGet(config, "monitor", "title")
  if tmp:
    monitor_dict["title"] = tmp
  tmp = softConfigGet(config, "monitor", "monitor-url-list")
  if tmp:
    monitor_dict["_links"] = {"related_monitor": [{"href": url} for url in tmp.split()]}
  if service_config_list:
    service_list = []
    monitor_dict["_embedded"] = {"service": service_list}
    for service_config in service_config_list:
      service_dict = {}
      service_list.append(service_dict)
      service_name = service_dict["id"] = service_config.get("service", "name")
      service_dict["_links"] = {"status": {"href": "/public/%s/status.json" % service_name}}
      tmp = softConfigGet(service_config, "service", "title")
      if tmp:
        service_dict["title"] = tmp
      tmp = softConfigGet(service_config, "service", "interface-path")
      if tmp:
        service_dict["_links"]["interface"] = {"href": "/%s.html" % service_name}  # XXX hardcoded
      else:
        service_dict["_links"]["interface"] = {"href": "/default-promise-interface.html?service_name=%s" % service_name}  # XXX hardcoded
  with open(config.get("monitor", "monitor-hal-json"), "w") as fp:
    json.dump(monitor_dict, fp)
  # create symlinks from service configurations
  for service_config in service_config_list:
    service_name = service_config.get("service", "name")
    createSymlinksFromConfig((config, "monitor", "public-folder"), (service_config, "service", "public-path-list"), service_name)
    createSymlinksFromConfig((config, "monitor", "private-folder"), (service_config, "service", "private-path-list"), service_name)
  # put promises to a cron file
  # XXX if manifest is modified then:  # add manifest to avoid to write every minutes on cron.d...
  service_pid_folder = config.get("monitor", "service-pid-folder")
  crond_folder = config.get("monitor", "crond-folder")
  cron_line_list = []
  for service_config in service_config_list:
    service_name = service_config.get("service", "name")
    service_status_path = "%s/%s/status.json" % (public_folder, service_name)
    mkdirAll(os.path.dirname(service_status_path))
    service_cron_path = os.path.join(crond_folder, service_name)
    cron_line_list.append("%s %s %s %s " % (
      service_config.get("service", "frequency"),
      promise_runner_path,
      os.path.join(service_pid_folder, "%s.pid" % service_name),
      service_status_path,
    ) + service_config.get("service", "promise-path").replace("%", "\\%"))
  with open(crond_folder + "/monitor-promises", "w") as fp:
    fp.write("\n".join(cron_line_list))
  # create symlinks from monitor.conf
  createSymlinksFromConfig((config, "monitor", "public-folder"), (config, "monitor", "public-path-list"))
  createSymlinksFromConfig((config, "monitor", "private-folder"), (config, "monitor", "private-path-list"))
  return 0

def loadConfig(pathes):
  config = ConfigParser.ConfigParser()
  config.read(pathes)
  return config

def softConfigGet(config, *args, **kwargs):
  try:
    return config.get(*args, **kwargs)
  except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
    return None

def createSymlinksFromConfig(destination_folder_config_tuple, source_list_config_tuple, service_name=""):
  destination_folder = softConfigGet(*destination_folder_config_tuple)
  if destination_folder:
    source_path_str = softConfigGet(*source_list_config_tuple)
    if source_path_str:
      for path in source_path_str.split():
        dirname = os.path.join(destination_folder, service_name)
        try:
          mkdirAll(dirname)  # could also raise OSError
          os.symlink(path, os.path.join(dirname, os.path.basename(path)))
        except OSError, e:
          if e.errno != os.errno.EEXIST:
            raise

def newServiceName(name, name_dict):
  part = name
  count = 1
  while name in name_dict:
    name = part + "_" + str(count)
    count += 1
  return name

def mkdirAll(path):
  try:
    os.makedirs(path)
  except OSError, e:
    if e.errno == os.errno.EEXIST and os.path.isdir(path):
      pass
    else: raise

if __name__ == "__main__":
  sys.exit(main())