#!/usr/bin/python
# The MIT License (MIT)

# Copyright (c) 2016 Shaun Harker

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from hillmodel import *
import itertools, sys, numpy, json

# Analyze
# "simulation_results" is an object of the form
#     { "network" : network_spec_file, "variables" : varnames, "parameter" : parameter, 
#          "times" : times, "timeseries" : [ [],[],[], ... ] }
#     "timeseries[i]" gives the list of values for the variables at time "times[i]""
#     in the order they appear in "variables"

def Analyze(simulation_results):
  # Number of variables
  D = len(simulation_results["variables"])
  # Number of time points
  N = len(simulation_results["timeseries"])
  #  Produce the tail-end (last half) of the time-series for each variable
  tail = simulation_results["timeseries"][N/2:]
  # Produce labels for each regime of increasing/decreasing pattern
  labels = [ sum([ 2**d if x[d] > y[d] else 2**(d+D) for d in range(0,D)]) for x,y in zip(tail,tail[1:])]
  # Return labels, elminating consecutive duplicates
  return [x[0] for x in itertools.groupby(labels)]

def Simulation(model,parameter,settings=[0.0,30.0,.01]):
  # Set initial condition
  y0 = numpy.array([1.0 for x in range( model.dim() )]) 
  # Settings variables (start, end, step)
  t0, t1, dt = settings
  # Integrate
  times, timeseries, varnames = model.simulateHillModel(y0,t0,t1,dt) 
  # Return result
  return { "variables" : varnames, "parameter" : parameter, 
           "times" : times, "timeseries" : [ x.tolist() for x in timeseries] }

def SimulationDatabase(network_spec_file,parameter_file,simulation_database_file):
  # Hill function exponent
  hillexp = 10
  # Read Network Specification File
  with open(network_spec_file) as f:
    network_spec_string = f.read()
  # Open output file for writing
  simulation_database = open(simulation_database_file,'w')
  # Iterate through parameters in input file
  with open(parameter_file) as f:
    for line in f:
      # Parse the input line
      parameter_line = json.loads(line)
      parameter_index = parameter_line["ParameterIndex"]
      parameter = parameter_line["Parameter"]
      # Build a Hill Model
      model = hillmodel(network_spec_string,parameter,hillexp)
      # Find a numerical solution to the Hill Model
      simulation_result = Simulation(model,parameter)
      # Product a qualitative summary of the numerical solution
      simulation_summary = Analyze(simulation_result)
      # Write the results to the output file
      simulation_database.write(json.dumps({"ParameterIndex":parameter_index,"Parameter":parameter,"SimulationSummary":simulation_summary}) + '\n' )
  # Close the output file and return
  simulation_database . close ()

if __name__ == "__main__":
  SimulationDatabase(sys.argv[1], sys.argv[2], sys.argv[3])

