#!{{ python }}
# -*- coding: utf-8 -*-

import sys
import os
import subprocess
import json
import psutil
import time
from shutil import copyfile
import glob
import argparse
import traceback

def parseArguments():
  """
  Parse arguments for monitor collector instance.
  """
  parser = argparse.ArgumentParser()
  parser.add_argument('--pid_path',
                      help='Path where the pid of this process will be writen.')
  parser.add_argument('--output',
                      help='The Path of file where Json result of this promise will be saved.')
  parser.add_argument('--promise_script',
                      help='Promise script to execute.')
  parser.add_argument('--promise_name',
                      help='Title to give to this promise.')
  parser.add_argument('--promise_type',
                      default='status',
                      help='Type of promise to execute. [status, report].')
  parser.add_argument('--monitor_url',
                      help='Monitor Instance website URL.')
  parser.add_argument('--history_folder',
                      help='Path where old result file will be placed before generate a new json result file.')
  parser.add_argument('--instance_name',
                      default='UNKNOWN Software Instance',
                      help='Software Instance name.')
  parser.add_argument('--hosting_name',
                      default='UNKNOWN Hosting Subscription',
                      help='Hosting Subscription name.')

  return parser.parse_args()

def main():
  parser = parseArguments()

  if os.path.exists(parser.pid_path):
    with open(parser.pid_path, "r") as pidfile:
      try:
        pid = int(pidfile.read(6))
      except ValueError:
        pid = None
      if pid and os.path.exists("/proc/" + str(pid)):
        print("A process is already running with pid " + str(pid))
        return 1
  start_date = ""
  with open(parser.pid_path, "w") as pidfile:
    process = executeCommand(parser.promise_script)
    ps_process = psutil.Process(process.pid)
    start_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ps_process.create_time()))
    pidfile.write(str(process.pid))

  status_json = generateStatusJsonFromProcess(process, start_date=start_date)

  status_json['_links'] = {"monitor": {"href": parser.monitor_url}}
  status_json['title'] = parser.promise_name
  status_json['instance'] = parser.instance_name
  status_json['hosting_subscription'] = parser.hosting_name
  status_json['type'] = parser.promise_type

  # Save the lastest status change date (needed for rss)
  status_json['change-time'] = ps_process.create_time()
  if os.path.exists(parser.output):
    with open(parser.output) as f:
      try:
        last_result = json.loads(f.read())
        if status_json['status'] == last_result['status'] and last_result.has_key('change-time'):
          status_json['change-time'] = last_result['change-time']
      except ValueError:
        pass

  updateStatusHistoryFolder(
    parser.promise_name,
    parser.output,
    parser.history_folder,
    parser.promise_type
  )
  with open(parser.output, "w") as outputfile:
    json.dump(status_json, outputfile)
  os.remove(parser.pid_path)

def updateStatusHistoryFolder(name, status_file, history_folder, promise_type):
  history_path = os.path.join(history_folder)
  if not os.path.exists(status_file):
    return
  if not os.path.exists(history_folder):
    return
  if not os.path.exists(history_path):
    try:
      os.makedirs(history_path)
    except OSError, e:
      if e.errno == os.errno.EEXIST and os.path.isdir(history_path):
        pass
      else: raise
  with open(status_file, 'r') as sf:
    try:
      status_dict = json.loads(sf.read())
    except ValueError:
      traceback.print_exc()
      return

  if promise_type == 'status':
    filename = '%s.history.json' % name
    history_file = os.path.join(history_path, filename)
    # Remove links from history (not needed)
    status_dict.pop('_links', None)
    if not os.path.exists(history_file):
      with open(history_file, 'w') as f_history:
        data_dict = {
          "date": time.time(),
          "data": [status_dict]
        }
        f_history.write(json.dumps(data_dict))
    else:
      # Remove useless informations
      status_dict.pop('hosting_subscription', '')
      status_dict.pop('title', '')
      status_dict.pop('instance', '')
      status_dict.pop('type', '')

      with open (history_file, mode="r+") as f_history:
        f_history.seek(0,2)
        position = f_history.tell() -2
        f_history.seek(position)
        #f_history.write(',%s]}' % str(status_dict))
        f_history.write('%s}' % ',{}]'.format(json.dumps(status_dict)))
  elif promise_type == 'report':
    # keep_item_amount = 3
    filename = '%s.history.json' % (
      name)

    copyfile(status_file, os.path.join(history_path, filename))
    """# Don't let history foler grow too much, keep xx files
    file_list = filter(os.path.isfile,
        glob.glob("%s/*.%s.history.json" % (history_path, promise_type))
      )
    file_count = len(file_list)
    if file_count > keep_item_amount:
      file_list.sort(key=lambda x: os.path.getmtime(x))
      while file_count > keep_item_amount:
        to_delete = file_list.pop(0)
        try:
          os.unlink(to_delete)
          file_count -= 1
        except OSError:
          raise"""

def generateStatusJsonFromProcess(process, start_date=None, title=None):
  stdout, stderr = process.communicate()
  try:
    status_json = json.loads(stdout)
  except ValueError:
    status_json = {}
  if process.returncode != 0:
    status_json["status"] = "ERROR"
  elif not status_json.get("status"):
    status_json["status"] = "OK"
  if stderr:
    status_json["message"] = stderr
  if start_date:
    status_json["start-date"] = start_date
  if title:
    status_json["title"] = title
  return status_json


def executeCommand(args):
  return subprocess.Popen(
    args,
    #cwd=instance_path,
    #env=None if sys.platform == 'cygwin' else {},
    stdin=None,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
  )

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