
########################################################################################################################
# Copyright (c) 2015, University of Osnabrueck                                                                         #
#   All rights reserved.                                                                                               #
#                                                                                                                      #
#   Redistribution and use in source and binary forms, with or without modification, are permitted provided that the   #
#   following conditions are met:                                                                                      #
#                                                                                                                      #
#   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following#
#       disclaimer.                                                                                                    #
#                                                                                                                      #
#   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       #
#       following disclaimer in the documentation and/or other materials provided with the distribution.               #
#                                                                                                                      #
#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, #
#   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  #
#   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, #
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR    #
#   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  #
#   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE   #
#   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                           #
########################################################################################################################
import subprocess
import numpy
import marshal
import time
import datetime
import os
import StringIO
import sys

import pp

from src.util import geometryHelper
from src import globals as gl


def createTypeString(config):

    POINT = 0
    LINE = 1
    AREA = 2
    CUBIC = 3
    LIST = 4

    type = config["receiverType"]
    minx = config["borders"][0]
    maxx = config["borders"][2]
    miny = config["borders"][1]
    maxy = config["borders"][3]
    step = config["stepSize"]
    minz = config["coverageLevel"]
    maxz = config["coverageMaxLevel"]
    lx = (int)(abs(maxx - minx) / step)
    ly = (int)(abs(maxy - miny) / step)
    sx = sy = sz = step


    if type == POINT:
        px = config["receivers"][0][0]
        py = config["receivers"][0][1]
        pz = config["receivers"][0][2]
        return str(POINT) + " " + str(px) + " " + str(py) + " " + str(pz)

    elif type == LINE:
        line = config["receivers"][0]
        start, end, step = line
        return str(LINE) + " " + str(start[0]) + " " + str(start[1]) + " " + str(start[2]) + " " + str(end[0]) + " " + str(end[1]) + " " + str(end[2]) + " " + str(step)

    elif type == AREA:
        return str(AREA) + " " + str(minx) + " " + str(miny) + " " + str(maxx) + " " + str(maxy) + " " + str(minz) + " " + str(sx) + " " + str(sy)

    elif type == CUBIC:
        return str(CUBIC) + " " + str(minx) + " " + str(miny) + " " + str(minz) + " " + str(maxx) + " " + str(maxy) + " " + str(maxz) + " " + str(sx) + " " + str(sy) + " " + str(sz)
    elif type == LIST:
        receivers = config["receivers"]
        out = str(LIST)
        out += " " + str(len(receivers))
        for receiver in receivers:
            out += " " + str(receiver[0]) + " " + str(receiver[1]) + " " + str(receiver[2])
        return out


    else:
        print "unsupported type"
        sys.exit()

    return "false"


def calculateSingle(transmitter, config, buildingsPolys, terrainPolys,
                    buildingsEdges, terrainEdges, rayFolder, typeString, receiverFile):


    #print typeString

    result = []
    #if not geometryHelper.inBuilding(numpy.array(transmitter), polygons):
    blub = ""
    try:
        blub = subprocess.check_output(['src/launcher/launcher',
                                        buildingsPolys, terrainPolys, buildingsEdges, terrainEdges, rayFolder,
                                        str(typeString),
                                        str(receiverFile),
                                        #Unused
                                        str("dummy"), str("dummy"),
                                        str("dummy"), str("dummy"),
                                        str("dummy"),
                                        #Unused finish
                                        str(transmitter[0]), str(transmitter[1]), str(transmitter[2]),
                                        str(config["rayNumber"]),
                                        str(config["maxIterations"]),
                                        str(config["receiveThreshold"]),
                                        str(config["diffractionThreshold"]),
                                        str(config["reflectionPart"]),
                                        str(config["wavelength"]),
                                        str(int(config["interference"])),
                                        str(config["maxRange"]),
                                        str(int(config["debugRays"])),
                                        str(int(config["debugLevel"])),
                                        str(config["deadDistance"]),
                                        str(config["scatteringPart"]),
                                        str(config["timeout"])],
                                       stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        #gl.logger.error( e )
        blub = e.output
        print "error", blub

    logfile = open("logc.txt", "w")
    logfile.write(blub)
    logfile.close()
    """
    #else:
        #almost deprecated
        minx = config["borders"][0]
        maxx = config["borders"][2]
        miny = config["borders"][1]
        maxy = config["borders"][3]
        step = config["stepSize"]
        result = numpy.zeros(((maxx - minx) / step, (maxy - miny) / step)).tolist()
        print "transmitter: ", transmitter, "is in building, dont calculate!"
        # print result
    """
    return result


def calculateTransmitterParallel(coveragefolder, buildingsPolys, terrainPolys, buildingsEdges, terrainEdges, rayFolder,
                                 transmitters, config, receiverfile):
    if config["preprop"]:
        print "extracting edges"
        try:
            blub = subprocess.check_output(['src/launcher/edges',
                                            buildingsPolys, terrainPolys, buildingsEdges, terrainEdges],
                                           stderr=subprocess.STDOUT)
            gl.logger.debug("Cout Edges: " + str(blub))
        except subprocess.CalledProcessError as e:
            print "failed to extract edges, see logfile for further information"
            gl.logger.error(str(e))
            sys.exit()

    print "start launcher"
    now = datetime.datetime.now()
    gl.logger.info( "starting at " + str(now.hour) + ":" + str(now.minute) + ":" + str(now.second))
    oldtime = time.time()

    #workers = config["numberWorkers"]
    job_server = pp.Server(ppservers=config["ppServers"], secret="rjn8809nesjn")
    jobs = []
    #polygons = geometryHelper.getPolygons(buildingsPolys)
    for transmitter in transmitters:
        transmitter = numpy.array(transmitter).tolist()
        jobs.append(job_server.submit(calculateSingle, (
            transmitter,
            config,
            buildingsPolys,
            terrainPolys,
            buildingsEdges,
            terrainEdges,
            rayFolder,
            createTypeString(config),
            receiverfile), (), ("subprocess", "geometryHelper", "numpy")))
    for job, transmitter in zip(jobs, transmitters):
        result = job()
        gl.logger.debug("Launcher-Cout for transmitter " + str(transmitter) + ": " +str(result))
        #print "Launcher-Cout for transmitter " + str(transmitter) + ": " +str(result)

    job_server.destroy()
    now = datetime.datetime.now()
    gl.logger.info("finishing at " + str(now.hour) + ":" + str(now.minute) + ":" + str(now.second))
    gl.logger.info("finished in " +  str(time.time() - oldtime) + " seconds")
	




