import json
import java.math.BigInteger as BigInteger
import org.python.core.PyLong as PyLong
import org.python.core.PyFloat as PyFloat
import traceback
import datetime

run("Devices/Elements")

def get_processing_parameters(stream_value):
    return json.loads(stream_value.getValue("processing_parameters"))  

def _create_tables(paths, stream_value, data_type, shape, images):
    root = paths["root"]
    create_dataset(paths["image"], data_type, dimensions = [images, shape[0], shape[1]])
    create_dataset(paths["pid"], 'l', dimensions = [images])
    create_dataset(paths["timestamp_str"], 's', dimensions = [images])
    for id in stream_value.identifiers:
        val = stream_value.getValue(id)
        if id == "image":
            pass
        elif id == "processing_parameters":                                                                     
            val = json.loads(val)                
            for key in val.keys():
                if val[key] is not None and isinstance(val[key], dict):    
                    for k in val[key].keys():
                        set_attribute(paths["image"], key + " " + k , "" if val[key][k] is None else val[key][k] )               
                else:  
                    set_attribute(paths["image"], key, "" if val[key] is None else val[key] )               
        elif isinstance(val, PyArray):
            create_dataset(root + id, 'd', dimensions = [images, len(val)])                                
        elif isinstance(val, PyLong):
            create_dataset(root + id, 'l', dimensions = [images])                
        elif isinstance(val, PyFloat):
            create_dataset(root + id, 'd', dimensions = [images])                
        else:   
            print "Unmanaged stream type: ", val, type(val)
            pass
    

def _append_frame(paths, stream_value, index, data_type, shape):
    print "Saving frame :", index
    #append_dataset(paths["image"], data, index, type = data_type)    
    root = paths["root"]
    append_dataset(paths["image"], stream_value.getValue("image"),[index,0,0], type = data_type,  shape=[1, shape[0], shape[1]])      
    append_dataset(paths["pid"], stream_value.getPulseId(), index)
    append_dataset(paths["timestamp_str"], datetime.datetime.fromtimestamp(stream_value.timestampNanos/1e9).strftime('%Y-%m-%d %H:%M:%S.%f'), index)   

    for id in stream_value.identifiers:
        try:
            val = stream_value.getValue(id)
            if id == "image":
                pass
            elif isinstance(val, PyArray):
                append_dataset(root + id, val, index)
            elif isinstance(val, PyLong):
                append_dataset(root + id, int(val), index)
            elif isinstance(val, PyFloat):
                append_dataset(root + id, float(val), index)
            else:      
                pass
        except:
            print id, val
            traceback.print_exc()
       
    #print "Saved frame: ", index


def _write_metadata(paths, camera, images, interval):
    root = paths["root"]    
    set_attribute(root, "Camera", camera)
    set_attribute(root, "Images", images)
    set_attribute(root, "Interval", interval)
    cam_type = get_camera_type(camera)
    set_attribute(root, "Type", cam_type)
    if cam_type=="ELECTRONS":
        set_attribute(root, "Screen", caget(camera + (":POSITION" if (camera.startswith("DSRM")) else ":GET_SCREEN1_POS"), 's'))
        set_attribute(root, "Filter", caget(camera + ":GET_FILTER", 's'))

    
def save_camera_data(server, images = 1, interval = -1, root = "/camera1", parallel = True, pause = False):
    stream_value = server.stream.take()
    if stream_value is None:
        server.waitNext(10000)
        stream_value = server.stream.take()
    if not root.endswith('/'):
        root = root + "/"
    camera = get_processing_parameters(stream_value)["camera_name"]
    paths = {"root": root, "image":root+"image", "pid":root+"/pulse_id", "timestamp_str":root+"/timestamp_str"}    
    shape = [stream_value.getValue("height"),stream_value.getValue("width")]
    data_type = stream_value.getValue("image").typecode    
    tasks = []  
    if pause:
        server.paused = True
    try:    
        for i in range(images):    
            #print i
            if i==0:                                
                _create_tables(paths, stream_value, data_type, shape, images)                
                _write_metadata(paths, camera, images, interval)            
            start = time.time()
            stream_value = server.stream.take()
            if parallel:                                
                tasks.extend( fork((_append_frame,(paths, stream_value, i, data_type, shape)),) )
            else:
                print "append"
                _append_frame(paths, stream_value, i, data_type, shape)
            print "OK"
            if i< (images-1):
                if interval<=0:
                    print "WAITING"
                    server.stream.waitCacheChange(10000)                            
                else:
                    print "Other"
                    sleep_time = float(interval)/1000.0 - (time.time()-start)
                    time.sleep(max(sleep_time,0))    
    finally:      
        if pause:
            server.paused = False
        pass
    data_file = get_exec_pars().path
    #print "Waiting finish : ", data_file
    join(tasks)
    #print "Done"
    return data_file

def save_camera_snapshot(server, file, format = "png"):
    ImageBuffer.saveImage(server.output, file, "png")