
"""
Creates a multiprocess, multithread application to detect high
readings.

See https://www.assemblesoftware.com/examples/

"""

import sys
import os
import math

sys.path.append(os.path.abspath("../../IoTPy/multiprocessing"))
sys.path.append(os.path.abspath("../../IoTPy/core"))
sys.path.append(os.path.abspath("../../IoTPy/agent_types"))
sys.path.append(os.path.abspath("../../IoTPy/helper_functions"))

# multicore is in multiprocessing
from multicore import shared_memory_process, Multiprocess
from VM import VM
from distributed import distributed_process
# stream is in core
from stream import Stream
# op, merge, source, sink are in agent_types
from merge import zip_map
from source import source_float_file
from sink import stream_to_file
# accelerometer_agents are in ("./accelerometer_agents")
from accelerometer_agents import subtract_mean, magnitude_of_vector
from accelerometer_agents import simple_anomalies, quench

def detect_large_magnitude(sensor_name, filenames):
    # ----------------------------------------------------------------
    # COMPUTE FUNCTION f
    # ----------------------------------------------------------------
    def compute_func(in_streams, out_streams):
        """
        Detects anomalies in streams generated by triaxial sensors.

        Parameters
        ----------
        in_streams: list of Stream
          in_streams is a list of 3 streams indicating measurements
          in e, n, and z (for east, north, vertical) directions.
          These streams are generated by a triaxial sensor.
        out_streams: list of Stream
          out_streams has only one element, which is a
          Stream of int. An element of this stream is either
          1.0 or 0.0. An element is 1.0 to indicate that an
          anomaly was detected in in_streams and is 0.0 otherwise.

        """

        #------------------------------------------------------------------
        # DECLARE INTERNAL STREAMS
        #------------------------------------------------------------------
        # magnitudes is a stream of magnitudes of a stream of vectors
        # where each vector is given by its e, n, z values.
        magnitudes = Stream('magnitudes')
        anomaly_times_before_quenching = Stream('prior quench')
        anomaly_times_after_quenching = out_streams[0]

        #----------------------------------------------------
        # CREATE AGENTS
        #----------------------------------------------------
        # This agent generates streams of magnitudes of vectors
        # from streams of the components of the vectors.
        magnitude_of_vector(in_streams, out_stream=magnitudes)
        # This agent generates a stream of anomalies from
        # streams of magnitudes.
        simple_anomalies(
            in_stream=magnitudes,
            out_stream=anomaly_times_before_quenching,
            threshold=0.005)
        quench(
            in_stream=anomaly_times_before_quenching,
            out_stream=anomaly_times_after_quenching,
            QUENCH_TIME=4)
               
        # Agents that copy streams into files for  later analysis.
        stream_to_file(anomaly_times_after_quenching, 'local_anomalies.txt')

    # ----------------------------------------------------------------
    #  DEFINE SOURCES
    # ----------------------------------------------------------------
    def source(filename):
        """
        This function creates a source by reading a file of
        floats. The source generates an element every
        TIME_INTERVAL seconds and stops after NUM_STEPS
        number of steps if NUM_STEPS is not None and outputs
        the entire file if NUM_STEPS is None.

        Parameters
        ----------
        filename: str
          name of a file

        """
        return source_float_file(
            filename,
            time_interval=0, num_steps=None).source_func

    directions = ['e', 'n', 'z']
    proc_0 = distributed_process(
        compute_func=compute_func,
        in_stream_names=directions,
        out_stream_names=['out'],
        connect_sources=[
            (directions[i], source(filenames[i]))
            for i in range(len(directions))]
        )

    vm_0 = VM(
        processes=[proc_0],
        connections=[],
        publishers=[(proc_0, 'out', sensor_name)])
    vm_0.start()


if __name__ == '__main__':
    # filenames has data recorded from east, north,
    # and vertical directions from a sensor
    args = sys.argv

    detect_large_magnitude(
        sys.argv[1], sys.argv[2:]
        )
    
    # Example of a call to this function from the command line:
    #   detect_large_magnitude.py S1 S1.e.txt S1.n.txt S1.z.txt
    # Here S1 is the name of the publication and 
    # S1.e.txt S1.n.txt S1.z.txt are the source files for the
    # accelerometer readings in the three axes.
    
