 #
 # This file is part of ROA-Analysis
 #
 # Author: Samir Al-Sheikh (Freie Universitaet, Berlin)
 #         s.al-sheikh@fu-berlin.de
 #
 # MIT License
 #
 # Copyright (c) 2017 The ROA-Analysis authors
 #
 # 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 __future__ import division
import sys, os, csv, operator, matplotlib, pandas, numpy, re
from utils.parse import parse_shell, parse_cfg, parse_window
from utils.util import cc_refactoring
from datetime import datetime
from collections import Counter
import matplotlib.dates as mdates

config_file = os.path.dirname(os.path.abspath(__file__)) + '/config.txt'
if parse_cfg(0).ssh_enabled: matplotlib.use('Agg')
import matplotlib.pyplot as plt

reasons = {'-3':'No File (earlier unreachability)', '-1':'File empty',
           '-2':'Client unreachable', '0':'Server unreachable', '1':'Reachable'}

## Options for the shell
options = 'i:p:!c'

def get_options():
  return options

def main():

  ## Parse shell arguments and RPKI Cache Server informations and build up file system
  args = parse_shell(options); cfg = parse_cfg(args)
  if not os.path.exists(cfg.archive_an + 'Reach/Plots'):
    os.makedirs(cfg.archive_an + 'Reach/Plots')

  ccs = sorted([f for f in os.listdir(cfg.archive_an + 'Reach/') if f.startswith('reach.') \
             and f.endswith('.csv')])
  result = pandas.DataFrame()

  ## Calculate the percentage amount of every reachability reason for every collector
  for cc in ccs:
    with open(cfg.archive_an + 'Reach/' + cc, 'r') as reach_file:
      data = sorted(csv.reader(reach_file, delimiter=','), key=operator.itemgetter(0))
    data_inv = parse_window(args.interval, data, 0, 0)
    start = datetime.strptime(data_inv[0][0], '%Y%m%d.%H%M').strftime('%b %d ')
    end = datetime.strptime(data_inv[-1][0], '%Y%m%d.%H%M').strftime('until %b %d, %Y')

    data = [d[1] for d in parse_window(args.interval, data, 0, 0)]
    data_cnt = Counter(data)

    for k in data_cnt.keys(): data_cnt[k] = (data_cnt[k] / len(data)) * 100
    df = pandas.DataFrame(data_cnt, index=[0])
    df['Collector'] = cc.split('.')[1]
    result = pandas.concat([result, df.set_index('Collector')])

  ## Substitute the enums with the reasons
  columns = ','.join(result.columns.tolist())
  pattern = re.compile('|'.join('(%s)' % r for r in reasons))
  lk = dict((i + 1, j) for i, j in enumerate(reasons.itervalues()))
  columns = pattern.sub(lambda x: x.expand(lk[x.lastindex]), columns)
  result.columns = columns.split(',')
  result.drop('Reachable', axis=1, inplace=True)

  for i in [s for s in result.index if 'RTR' in s]:
    tmp = result.loc[i, 'Server unreachable']
    result.loc[i, 'Server unreachable'] = result.loc[i, 'Client unreachable']
    result.loc[i, 'Client unreachable'] = tmp

  ## Refactoring collector names
  result.index = cc_refactoring(list(result.index.values))
  result.sort_index(inplace=True)

  ## Debug print
  print result

  ## Export Dataframe to table file
  if not os.path.exists(cfg.archive_an + 'Reach/Table'): os.makedirs(cfg.archive_an + 'Reach/Table')
  print '\nPlot: ' + cfg.archive_an + 'Reach/Table/reach.all_collectors.csv'
  result.to_csv(cfg.archive_an + 'Reach/Table/reach.all_collectors.csv', sep='\t')

  return
'''
  plot(result, cfg.archive_an, start, end)

def plot(result, archive_an, start, end):
  """ Plot the reachability for a collector """

  ## Plotting
  matplotlib.rcParams['figure.figsize'] = (20, 10); matplotlib.rcParams['figure.dpi'] = 80
  matplotlib.rcParams['figure.facecolor'] = 'w'; matplotlib.rcParams['figure.edgecolor'] = 'k'
  name_len = len(list(result.columns.values))
  ax = result.plot.bar(rot=0, stacked=True, color=['moccasin', 'lightgrey', 'powderblue', 'salmon'])
  labeling(ax); ax.autoscale_view()
  lgd = plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=12, mode='expand', borderaxespad=0.)
  title_offset = 1.07 + (int(name_len/12)+1) * 0.01
  plt.title('Unreachability for all collectors - ' + start + end, y=title_offset)
  plt.ylabel('Reasons for Unreachability [%]')
  print 'Plot: ' + archive_an + 'Reach/Plots/plots.reach.all.pdf'
  plt.savefig(archive_an + 'Reach/Plots/plots.reach.all.pdf', bbox_inches='tight')
  return

def labeling(ax):
  """ Label the stacked bar chart """

  for p in ax.patches:
    b = p.get_bbox()
    val = '{:.2f}'.format(b.y1 - b.y0)

    ## Adjust maximum height for the box annotations
    if(b.height * ax.get_figure().dpi > 100 and b.height * ax.get_figure().dpi < 4000):
      ax.annotate(val, (b.x0 + (b.x1-b.x0)/2 - 0.12, (b.y0+(b.y1-b.y0)/2)-(b.y1-b.y0)*0.1))#, rotation=90)

    elif(b.height * ax.get_figure().dpi > 4000):
      ax.annotate(val, (b.x0 + (b.x1-b.x0)/2 - 0.13, (b.y0+(b.y1-b.y0)/2)))#, rotation=90)
'''
if __name__ == '__main__':
    main()
