"""Copyright 2008 Orbitz WorldWide

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License."""

import cairocffi as cairo
import itertools
import json
import math
import pytz
import re
import six

from datetime import datetime, timedelta
from io import BytesIO
from six.moves import range
from six.moves.urllib.parse import unquote_plus

from .datalib import TimeSeries
from ..utils import to_seconds


INFINITY = float('inf')

colorAliases = {
    'black': (0, 0, 0),
    'white': (255, 255, 255),
    'blue': (100, 100, 255),
    'green': (0, 200, 0),
    'red': (255, 0, 0),
    'yellow': (255, 255, 0),
    'orange': (255, 165, 0),
    'purple': (200, 100, 255),
    'brown': (150, 100, 50),
    'cyan': (0, 255, 255),
    'aqua': (0, 150, 150),
    'gray': (175, 175, 175),
    'grey': (175, 175, 175),
    'magenta': (255, 0, 255),
    'pink': (255, 100, 100),
    'gold': (200, 200, 0),
    'rose': (200, 150, 200),
    'darkblue': (0, 0, 255),
    'darkgreen': (0, 255, 0),
    'darkred': (200, 00, 50),
    'darkgray': (111, 111, 111),
    'darkgrey': (111, 111, 111),
}

# This gets overridden by graphTemplates.conf
defaultGraphOptions = dict(
    background='white',
    foreground='black',
    majorline='rose',
    minorline='grey',
    linecolors=('blue,green,red,purple,brown,yellow,aqua,grey,'
                'magenta,pink,gold,rose'),
    fontname='Sans',
    fontsize=10,
    fontbold='false',
    fontitalic='false',
)

# X-axis configurations (copied from rrdtool, this technique is evil & ugly
# but effective)
SEC = 1
MIN = 60
HOUR = MIN * 60
DAY = HOUR * 24
WEEK = DAY * 7
MONTH = DAY * 31
YEAR = DAY * 365

# Set a flag to indicate whether the '%l' option can be used safely.
# On Windows, in particular the %l option in strftime is not supported.
# On Linux, the %l option can also fail silently.
# (It is not one of the documented Python formatters).
try:
    if datetime.now().strftime("%a %l%p"):
        percent_l_supported = True
    else:
        percent_l_supported = False
except ValueError:
    percent_l_supported = False

xAxisConfigs = (
    dict(seconds=0.00,
         minorGridUnit=SEC,
         minorGridStep=5,
         majorGridUnit=MIN,
         majorGridStep=1,
         labelUnit=SEC,
         labelStep=5,
         format="%H:%M:%S",
         maxInterval=10*MIN),
    dict(seconds=0.07,
         minorGridUnit=SEC,
         minorGridStep=10,
         majorGridUnit=MIN,
         majorGridStep=1,
         labelUnit=SEC,
         labelStep=10,
         format="%H:%M:%S",
         maxInt
erval=20*MIN),
    dict(seconds=0.14,
         minorGridUnit=SEC,
         minorGridStep=15,
         majorGridUnit=MIN,
         majorGridStep=1,
         labelUnit=SEC,
         labelStep=15,
         format="%H:%M:%S",
         maxInterval=30*
MIN),
    dict(seconds=0.27,
         minorGridUnit=SEC,
         minorGridStep=30,
         majorGridUnit=MIN,
         majorGridStep=2,
         labelUnit=MIN,
         labelStep=1,
         format="%H:%M",
         maxInterval=2*HOUR),
    dict(seconds=0.5,
         minorGridUnit=MIN,
         minorGridStep=1,
         majorGridUnit=MIN,
         majorGridStep=2,
         labelUnit=MIN,
         labelStep=1,
         format="%H:%M",
         maxInterval=2*HOUR),
    dict(seconds=1.2,
         minorGridUnit=MIN,
         minorGridStep=1,
         majorGridUnit=MIN,
         majorGridStep=4,
         labelUnit=MIN,
         labelStep=2,
         format="%H:%M",
         maxInterval=3*HOUR),
    dict(seconds=2,
         minorGridUnit=MIN,
         minorGridStep=1,
         majorGridUnit=MIN,
         majorGridStep=10,
         labelUnit=MIN,
         labelStep=5,
         format="%H:%M",
         maxInterval=6*HOUR),
    dict(seconds=5,
         minorGridUnit=MIN,
         minorGridStep=2,
         majorGridUnit=MIN,
         majorGridStep=10,
         labelUnit=MIN,
         labelStep=10,
         format="%H:%M",
         maxInterval=12*HOUR),
    dict(seconds=10,
         minorGridUnit=MIN,
         minorGridStep=5,
         majorGridUnit=MIN,
         majorGridStep=20,
         labelUnit=MIN,
         labelStep=20,
         format="%H:%M",
         maxInterval=1*DAY),
    dict(seconds=30,
         minorGridUnit=MIN,
         minorGridStep=10,
         majorGridUnit=HOUR,
         majorGridStep=1,
         labelUnit=HOUR,
         labelStep=1,
         format="%H:%M",
         maxInterval=2*DAY),
    dict(seconds=60,
         minorGridUnit=MIN,
         minorGridStep=30,
         majorGridUnit=HOUR,
         majorGridStep=2,
         labelUnit=HOUR,
         labelStep=2,
         format="%H:%M",
         maxInterval=2*DAY),
    dict(seconds=100,
         minorGridUnit=HOUR,
         minorGridStep=2,
         majorGridUnit=HOUR,
         majorGridStep=4,
         labelUnit=HOUR,
         labelStep=4,
         format=percent_l_supported and "%a %l%p" or "%a %I%p",
         maxInterval=6*DAY),
    dict(seconds=255,
         minorGridUnit=HOUR,
         minorGridStep=6,
         majorGridUnit=HOUR,
         majorGridStep=12,
         labelUnit=HOUR,
         labelStep=12,
         format=percent_l_supported and "%m/%d %l%p" or "%m/%d %I%p",
         maxInterval=10*DAY),
    dict(seconds=600,
         minorGridUnit=HOUR,
         minorGridStep=6,
         majorGridUnit=DAY,
         majorGridStep=1,
         labelUnit=DAY,
         labelStep=1,
         format="%m/%d",
         maxInterval=14*DAY),
    dict(seconds=1000,
         minorGridUnit=HOUR,
         minorGridStep=12,
         majorGridUnit=DAY,
         majorGridStep=1,
         labelUnit=DAY,
         labelStep=1,
         format="%m/%d",
         maxInterval=365*DAY),
    dict(seconds=2000,
         minorGridUnit=DAY,
         minorGridStep=1,
         majorGridUnit=DAY,
         majorGridStep=2,
         labelUnit=DAY,
         labelStep=2,
         format="%m/%d",
         maxInterval=365*DAY),
    dict(seconds=4000,
         minorGridUnit=DAY,
         minorGridStep=2,
         majorGridUnit=DAY,
         majorGridStep=4,
         labelUnit=DAY,
         labelStep=4,
         format="%m/%d",
         maxInterval=365*DAY),
    dict(seconds=8000,
         minorGridUnit=DAY,
         minorGridStep=3.5,
         majorGridUnit=DAY,
         majorGridStep=7,
         labelUnit=DAY,
         labelStep=7,
         format="%m/%d",
         maxInterval=365*DAY),
    dict(seconds=16000,
         minorGridUnit=DAY,
         minorGridStep=7,
         majorGridUnit=DAY,
         majorGridStep=14,
         labelUnit=DAY,
         labelStep=14,
         format="%m/%d",
         maxInterval=365*DAY),
    dict(seconds=32000,
         minorGridUnit=DAY,
         minorGridStep=15,
         majorGridUnit=DAY,
         majorGridStep=30,
         labelUnit=DAY,
         labelStep=30,
         format="%m/%d",
         maxInterval=365*DAY),
    dict(seconds=64000,
         minorGridUnit=DAY,
         minorGridStep=30,
         majorGridUnit=DAY,
         majorGridStep=60,
         labelUnit=DAY,
         labelStep=60,
         format="%m/%d %Y"),
    dict(seconds=100000,
         minorGridUnit=DAY,
         minorGridStep=60,
         majorGridUnit=DAY,
         majorGridStep=120,
         labelUnit=DAY,
         labelStep=120,
         format="%m/%d %Y"),
    dict(seconds=120000,
         minorGridUnit=DAY,
         minorGridStep=120,
         majorGridUnit=DAY,
         majorGridStep=240,
         labelUnit=DAY,
         labelStep=240,
         format="%m/%d %Y"),
)

UnitSystems = {
    'binary': (
        ('Pi', 1024.0**5),
        ('Ti', 1024.0**4),
        ('Gi', 1024.0**3),
        ('Mi', 1024.0**2),
        ('Ki', 1024.0)),
    'si': (
        ('P', 1000.0**5),
        ('T', 1000.0**4),
        ('