import sys, os, errno
import numpy as np
import csv
import json
import copy
import math

def generate_classes(class_index_file):
    classes = {0: 'Background'}
    class_id = 0
    with open(class_index_file, 'r') as f:
        class_dict = json.load(f)
        for class_name in class_dict.keys():
            class_id += 1
            classes[class_id] = class_name
    return classes

def generate_classes_from_json(activity_index):
    with open(activity_index, 'r') as f:
        activities = json.load(f)
    idx = 0
    classes = {0: 'Background'}
    for activity_label in activities:
        idx += 1
        classes[idx] = activity_label
    return classes

def generate_video_mapping(file_index):
    video_dict = {}
    with open(file_index, 'r') as f:
        file_index_dict = json.load(f)
    for video in file_index_dict.keys():
        video_dict[os.path.splitext(video)[0]] = video
    return video_dict

def get_segments(data, classes, thresh, act_id, fps):
    segments = []
    vid = 'Background'
    find_next = False
    #global ACT_ID

    for l in data:
      # video name and sliding window length
      if "fg_name :" in l:
         vid = l.split('/')[-1] #[4]
         if len(vid)==0:
            vid = l.split('/')[-2]

      # frame index, time, confident score
      elif "frames :" in l:
         start_frame=int(l.split()[4])
         end_frame=int(l.split()[5])
         stride = int(l.split()[6].split(']')[0])

      elif "activity:" in l:
         label = int(l.split()[1])
         find_next = True

      elif "im_detect" in l:
         return vid, segments

      elif find_next: #Next temporal segment if it exists
         lc= l.strip()
         la= lc.strip('[')
         lb= la.strip(']')

         left_frame = int(math.floor(float(lb.split()[0]))*stride + start_frame)
         right_frame = int(math.floor(float(lb.split()[1]))*stride + start_frame)
         if left_frame > right_frame:
             left_frame, right_frame = right_frame, left_frame
         if left_frame == right_frame:
            if left_frame > 0:
                left_frame -= 1
            else:
                right_frame += 1
         score = float(lb.split()[2].split(']')[0])

         if score > thresh:
           #ACT_ID = ACT_ID + 1
           act_id += 1
           if label not in classes:
             classes[label] = "out_of_bounds"

           activity = {'activity' : classes[label], 'activityID': act_id, 'presenceConf': score, 'alertFrame': right_frame}
           frames = {left_frame : 1, right_frame : 0}
           #TODO: better way to get video extension
           activity['localization'] = { vid + ".mp4" : frames}
           segments.append(activity)


def compute_absolute_frame(relative_frame, start_frame, stride):
    return int(math.floor(relative_frame*stride + start_frame))

def get_video_name(log_instance, video_dict):
    if os.path.basename(log_instance.fg_name) in video_dict:
        return video_dict[os.path.basename(log_instance.fg_name)]
    else:
        raise Exception("Video not present in file index")


def get_log_segment(log_instance, classes, video_dict, test_classes, thresh, act_id, fps):
    start_frame, end_frame, stride = log_instance.frames
    video_name = get_video_name(log_instance, video_dict)
    segments = []
    for activity_index, temporal_boxes in log_instance.activities.iteritems():
        for i in range(temporal_boxes.shape[0]):
            if activity_index in classes.keys():
                class_label = classes[activity_index]
            else:
                class_label = "out_of_bounds"

            if test_classes is not None:
                if class_label not in test_classes.values():
                    continue
            relative_left_frame, relative_right_frame, presence_conf = \
                                                                temporal_boxes[i]

            absolute_left_frame = compute_absolute_frame(relative_left_frame,
                                                            start_frame, stride)
            absolute_right_frame = compute_absolute_frame(relative_right_frame,
                                                            start_frame, stride)

            if absolute_left_frame == absolute_right_frame:
                if absolute_left_frame > 0:
                    absolute_left_frame -= 1
                else:
                    absolute_right_frame += 1
            if float(presence_conf) > thresh:
                segments.append({
                    'activity': class_label,
                    'activityID': act_id,
                    'presenceConf': float(presence_conf),
                    'alert_frame': absolute_right_frame,
                    'localization': {video_name : {absolute_left_frame: 1,
                                                   absolute_right_frame: 0}}
                    })
                act_id += 1
    return segments, act_id

def sys_to_res(sys_out, classes, video_dict, test_classes, thresh, act_id, fps):
  predict_data = []
  res = {}
  act_dict = {}
  for log_instance in sys_out:
      video_name = get_video_name(log_instance, video_dict)
      if video_name in act_dict.keys():
          act_id = act_dict[video_name]
      else:
          act_id = 0
      segments, new_act_id = get_log_segment(log_instance,
                                             classes,
                                             video_dict,
                                             test_classes,
                                             thresh,
                                             act_id, fps)
      if video_name not in res:
          res[video_name] = []

      act_dict[video_name] = new_act_id
      res[video_name] += segments
  return res

def convert_log_to_json(test_logs, class_file, file_index, output_path, thresh = 0.05,
                        test_activity_index=None,
                        act_id=0, fps=25.0, use_json_class_index=False,
                        dump_individual=False):
    if use_json_class_index:
        classes = generate_classes_from_json(class_file)
    else:
        classes = generate_classes(class_file)
    video_dict = generate_video_mapping(file_index)
    if test_activity_index is not None:
        test_classes = generate_classes_from_json(test_activity_index)
    else:
        test_classes = None

    segmentations = sys_to_res(test_logs, classes,video_dict, test_classes, thresh, act_id, fps)
    if dump_individual:
        for vid, vinfo in segmentations.iteritems():
            vid_res = {'filesProcessed': [vid], 'activities': [vinfo]}
            video_name = os.path.splitext(video_name)[0] + ".json"
            outfile = open(file_path + video_name, 'w')
            json.dump(vid_res, outfile, indent=2)
    else:
        vid_res = {'filesProcessed': [], 'activities': []}
        for vid, vinfo in segmentations.iteritems():
            # TODO: pass video extension as a parameter
            vid_res['filesProcessed'].extend( [vid] )
            vid_res['activities'].extend( vinfo )

        outfile = open(output_path, 'w')
        json.dump(vid_res, outfile, indent=2)


def main():
    #assert len(sys.argv) == 2, "Usage: python log_analysis.py <test_log>"
    logfile = sys.argv[1]
    FPS = 25.0   # currently FPS=25
    ACT_ID = 0
    classes = generate_classes()
    sys_to_res(logfile, classes, 0.05, ACT_ID, FPS)

if __name__ == "__main__":
    main()
