#!/usr/bin/python

from Cheetah.Template import Template
import re

tag_re = re.compile('\\(([0-9A-F]{4}),([0-9A-F]{4})\\)')
vm_re = re.compile('(\\d+)(?:-(\\d*)(n?))?')

class diction_value:
    def __init__(self, vr, min_val, max_val, multiple):
        self.vr = vr
        self.min_val = min_val
        self.max_val = max_val
        self.multiple = multiple

    def __str__(self):
        return "VR: %s, min vals: %s, max_vals: %s, multiple: %s" % (self.vr, self.min_val, self.max_val, self.multiple)

def is_valid_standard_tag(tag):
    return ((tag & 0x00010000) == 0)

def generate_tags(tag):
    ret = []

    import re
    # Some tags have "x" values in them. Replace with F
    tag_high = tag.replace('x', 'F')
    # and replace with 0
    tag_low = tag.replace('x', '0')
    try:
        m_high = tag_re.match(tag_high)
        m_low  = tag_re.match(tag_low)

        int_high = int( "0x%s%s" % (m_high.group(1), m_high.group(2)), 16 )
        int_low = int( "0x%s%s" % (m_low.group(1), m_low.group(2)), 16 )

        # Take the difference between the "high" and "low" value. This will
        # leave just the "don't care" bits high
        diff = int_high - int_low

        diff_inv = ~diff
        # The inverted difference plus 1 makes the LSB "don't care" bit high.
        # When bitwise ANDed with the difference we obtain a value with just
        # the LSB "don't care" bit high
        incr = max((diff_inv + 1) & diff, 1)

        ret = range(int_low, int_high + incr, incr)
    except BaseException:
        ret = []

    return filter( is_valid_standard_tag, ret )

def parse_vm(vm):
    import re

    min_val = 1
    max_val = 1
    multiple = 1

    m = vm_re.match(vm)
    min_val = int(m.group(1))
    if m.group(3) is not None and len(m.group(3)) > 0:
        max_val = 0xFFFF
        if m.group(2) is not None and len(m.group(2)) > 0:
            multiple = int(m.group(2))
        else:
            multiple = 1
    elif m.group(2) is not None and len(m.group(2)) > 0:
        max_val = int(m.group(2))
        multiple = 1
    else:
        max_val = min_val
        multiple = 1

    return (min_val, max_val, multiple)

def parse_diction(diction):
    ret = {}
    for row in diction:
        row_tag = row['Tag']
        vr = None
        min_vals = None
        max_vals = None
        multiple = None

        if len(row['VR']) > 0:
            vr = format_vr(row['VR'])

            if len(row['VM']) > 0:
                (min_vals, max_vals, multiple) = parse_vm(row['VM'])

            ret.update(dict.fromkeys(generate_tags(row_tag),
                                     diction_value(vr, min_vals, max_vals, multiple)))

    return ret

def get_vr_map(diction_standard, diction_system):
    standard_map = parse_diction(diction_standard)
    system_map = parse_diction(diction_system)

    ret = {}

    for (tag, system_val) in system_map.iteritems():
        if tag in standard_map:
            standard_val = standard_map[tag]
            if system_val.vr is not None:
                standard_val.vr = system_val.vr
            if system_val.min_val is not None:
                standard_val.min_val = system_val.min_val
            if system_val.max_val is not None:
                standard_val.max_val = system_val.max_val
            if system_val.multiple is not None:
                standard_val.multiple = system_val.multiple
        else:
            standard_map[tag] = system_val

    # Special tags that don't belong in the dictionary
    del standard_map[0xfffee000]
    del standard_map[0xfffee00d]
    del standard_map[0xfffee0dd]

    return standard_map

def format_vr(vr):
    return "UNKNOWN_VR" if vr == "UN" else vr

def format_tag(tag):
    return "0x%08x" % (tag)

class gen_tag_vrs(Template):
    def __init__(self, diction_standard, diction_system):
        self.__vr_map = get_vr_map(diction_standard, diction_system)

    def vr_map(self):
        return self.__vr_map

def main(args):
    from csv import DictReader
    from tag_to_default_vr_cpp import tag_to_default_vr_cpp

    # VR map auto-generated from the standard document
    diction_standard = list(DictReader(open(args[0], "r")))
    # VR map used by the system to provide default VRs for
    # tags with conditional value representation
    diction_system = list(DictReader(open(args[1], "r")))

    vr_tmpl = tag_to_default_vr_cpp(diction_standard, diction_system)

    with open("../src/fume/tag_to_default_vr.cpp", "w") as tag_dict_file:
        tag_dict_file.write(str(vr_tmpl))

if __name__ == "__main__":
    import sys
    main(sys.argv[1:])


"""
## Single transformation DAG

Trigger with a config: `{"partner": "<partner_key>"}`
"""

from datetime import datetime, timedelta
import sys
import os

from airflow import DAG

from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator
from airflow.decorators import dag, task
from airflow.models import Variable
from airflow.models.baseoperator import chain

PATH = os.path.abspath(os.path.dirname(__file__))
SSDN_ENV = Variable.get('ssdn_env')

# Import local module
sys.path.insert(0, PATH)
import ssdn_assets

with DAG('ssdn_single_transform',
         default_args={'depends_on_past': False,
                       'email': ['airflow.example.org'],
                       'email_on_failure': False,
                       'email_on_retry': False,
                       'retries': 1,
                       'retry_delay': timedelta(minutes=5),
                       'env': {'MANATUS_CONFIG': SSDN_ENV}
                       },
         description='Single partner transform',
         tags=['ssdn', 'transform', 'configure', ],
         start_date=datetime(2022, 1, 1),
         schedule_interval='@quarterly',
         catchup=False,
         doc_md=__doc__,
         ) as dag:

    repo_update = BashOperator(
        task_id='repo_update',
        bash_command=f'bash {PATH}/ssdn_assets/repo_update.sh {Variable.get("ssdn_git_repos")}',
    )

    s3_upload = BashOperator(
        task_id='s3_upload',
        bash_command='whoami',
    )

    partner_transform = BashOperator(
        task_id=f'single_transform',
        bash_command='python3 -m manatus --profile ssdn -v transform -s {{ dag_run.conf["partner"] }} --to_console',
    )

    chain(repo_update, partner_transform, s3_upload)


from Core.Controller import Controller
from Models.Temp import Temp

class SearchController(Controller):
    def __init__(self):
        self.searchView=self.loadView("search")
        self.tempModel=Temp()
        self.searchText=self.tempModel._getNext("search")

    def _getLinks(self):
        from youtubesearchpython import VideosSearch
        search=VideosSearch(self.searchText,limit=10)
        results=search.result()
        results=results["result"]
        links=[]
        for result in results:
            links.append(result["link"])
        return links

    def _getInfo(self,link):
        from hurry.filesize import size
        import datetime
        from pytube import YouTube
        yt=YouTube(link)

        lengt=str(datetime.timedelta(seconds=yt.length)).split(":")
        if lengt[0]=="0":
            lengt=lengt[1]+":"+lengt[2]
        else:
            lengt=str().join(lengt)

        title=yt.title
        if len(title)>>30:
            title=title[:30]

        info = {
            "title":title,
            "length":lengt,
            "author":yt.author,
            "link":link}
        info["button text"]="{}\n{}".format(info["title"],info["length"],info["author"])
        info["popup text"]="Title:    {}\nDuration: {}\nChannel:  {}".format(info["title"],info["length"],info["author"])
        yt=None
        return info

    def _sortEntry(self,text):
        if "https://www.youtube.com/watch" in text:
            return "LINK"
        else:
            return "SEARCH"
    def _validateEntry(self,text):
        if len(text)>>2:
            return True
        else:
            return False
    def _validateLink(self,link):
        from pytube import YouTube
        try:
            yt=YouTube(link)
            return True
        except:
            return False

    def _getButtonsInfo(self):
        info=[]
        for link in self._getLinks():
            info.append(self._getInfo(link))
        return info

    def clickBack(self):
        self.close("home")
    def clickConfirm(self,link):
        self.tempModel._putNext("link",link)
        self.close("download")
    def clickSearch(self):
        text=self.searchView.searchEntry.get()
        if self._validateEntry(text):
            if self._sortEntry(text)=="LINK":
                self.clickConfirm(text)
            else:
                self.tempModel._putNext("search",text)
                self.close("search")
        else:
            self.homeView._update_errorlog("Short entry!")
    def main(self):
        self.searchView.main()
    def close(self,next):
        self.tempModel._putNext("frame",next)
        self.searchView.close()


import unittest, os, tempfile
import sys
import testlib

use_private = True
try:
    from private.qrt.ghostscript import GhostscriptPrivateTests
except ImportError:
    use_private = False
    print >>sys.stdout, "Skipping private tests"

class GhostscriptTest(testlib.TestlibCase):
    '''Test ghostscript/gs-esp/gs-gpl functionality'''

    def setUp(self):
        '''setUp'''
        self.tempdir = tempfile.mkdtemp(dir='/tmp',prefix="ghostscript-")
        self.ps = "./data/cups_testprint.ps"

    def tearDown(self):
        '''Clean up after each test_* function'''
        if os.path.exists(self.tempdir):
            testlib.recursive_rm(self.tempdir)

    def _check_mime_type(self, filename, mimetype):
        '''Checks the mime type of the file specified'''

        (rc, report) = testlib.cmd(["/usr/bin/file", "-b", os.path.join(self.tempdir, filename)])
        expected = 0
        result = 'Got exit code %d, expected %d\n' % (rc, expected)
        self.assertEquals(expected, rc, result + report)

        result = 'Mime type from file: %s, expected: %s\n' % (report, mimetype)
        self.assertEquals(report.rstrip(), mimetype, result)

    def test_ps2utils(self):
        '''Test ps2* utilities'''

        utils = ['ps2ascii', 'ps2epsi', 'ps2pdf', 'ps2pdf12', 'ps2pdf13', \
                  'ps2pdf14', 'ps2pdfwr', 'ps2ps', 'ps2ps2', 'ps2txt']
        if self.lsb_release['Release'] == 6.06:
            # These don't exist on Dapper
            utils.remove("ps2txt")
            utils.remove("ps2ps2")

        errors = 0
        errstr = ""
        for util in utils:
            self.out = os.path.join(self.tempdir, "out." + util[3:])
            rc, report = testlib.cmd([util, self.ps, self.out])
            expected = 0
            if rc != expected:
                result = '\'%s\' returned exit code %d, expected %d\n' % \
                         (util, rc, expected)
                errstr = errstr + result + report
                errors += 1

        self.assertEquals(errors, 0, errstr)

    def test_pdf2ps(self):
        '''Test pdf2ps utility'''

        conversions = ( 'case_Contact.pdf',
                        'case_howard_county_library.pdf',
                        'case_KRUU.pdf',
                        'case_OaklandUniversity.pdf',
                        'case_oxford_archaeology.pdf',
                        'case_Skegness.pdf',
                        'case_ubuntu_johnshopkins_v2.pdf',
                        'case_ubuntu_locatrix_v1.pdf',
                        'case_Wellcome.pdf' )

        if self.lsb_release['Release'] <= 8.04:
            ps_filetype = 'PostScript document text conforming at level 3.0'
        else:
            ps_filetype = 'PostScript document text conforming DSC level 3.0, Level 2'

        for filename in conversions:

            outfilename = filename.replace('.pdf', '.ps')

            (rc, report) = testlib.cmd(["/usr/bin/pdf2ps",
                                        "./data/" + filename,
                                        os.path.join(self.tempdir, outfilename)])
            expected = 0
            result = 'Got exit code %d, expected %d\n' % (rc, expected)
            self.assertEquals(expected, rc, result + report)

            # Let's check the mime-type to make sure it generated a valid PostScript file
            self._check_mime_type(outfilename, ps_filetype)

    def test_gs(self):
        '''Test gs executable(s)'''

        gs_bins = []
        if self.lsb_release['Release'] == 6.06:
            # Binaries split prior to Gutsy
            gs_bins = ['gs-esp', 'gs-gpl']
        else:
            gs_bins = ['gs']

        errors = 0
        errstr = ""
        for util in gs_bins:
            rc, report = testlib.cmd([util, '-sDEVICE=nullpage', '-dNOPAUSE', '--', self.ps])
            expected = 0
            if rc != expected:
                result = '\'%s\' returned exit code %d, expected %d\n' % \
                         (util, rc, expected)
                errstr = errstr + result + report
                errors += 1

        self.assertEquals(errors, 0, errstr)

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(GhostscriptTest))

    # Pull in private tests
    if use_private:
        suite.addTest(unittest.TestLoader().loadTestsFromTestCase(GhostscriptPrivateTests))

    rc = unittest.TextTestRunner(verbosity=2).run(suite)
    if not rc.wasSuccessful():
        sys.exit(1)


import requests, json

#uses covid-19 api to grab possible countries for data
def getKeys():
	endpoint = 'https://api.quarantine.country/'
	try:
		r= requests.get(endpoint)
		data = r.json()
		options = list(data['regions'].keys())
		options.sort()
		return options
	except:
		return []

#gathers covid-19 statistics based on country
def getStat(country):
	param = {"region":country}
	endpoint = 'https://api.quarantine.country/api/v1/summary/region'
	try:
		r = requests.get(endpoint, params=param)
		data = r.json()
		return data
	except:
		return []

#gathers the worldwide summary of covid-19 data
def getWorld():
	endpoint = 'https://api.quarantine.country/'
	try:
		r= requests.get(endpoint)
		data = r.json()
		return data
	except:
		return []


"""
One-thread parser  https://lalafo.kg/bishkek/kvartiry/prodazha-kvartir/
Parsing speed approximately ~ 120 items/s.
OS: Windows 10
"""

import json
import os
import sys
import time
import datetime
import pytz
import colorama
from colorama import Fore
from random import randrange
from openpyxl import Workbook
from openpyxl.styles import Font
from bs4 import BeautifulSoup
import requests
from winsound import MessageBeep, MB_OK, MB_ICONHAND
from tqdm import tqdm
import cursor

colorama.init(autoreset=True)
current_data_time = datetime.datetime.now().strftime("%d_%m_%Y_%H_%M")
current_data = datetime.datetime.now().strftime("%d_%m_%Y")
abspath_workdir = os.path.dirname((os.path.abspath(__file__)))

headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;'
                     '=0.8,application/signed-exchange;v=b3;q=0.9',
           'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ('
                         'KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'}

header_items = ["Number", "Advert id", "Advert url", "Main mobile phone", "Messenger phone_1",
                "Messenger phone_2", "Messenger phone_3", "Messenger phone 4", "Advert title", "Price",
                "Currency", "Created time", "Updated_time"]
MESS_LEN = 90
items_dict = {}
pagination = 0

def get_pag_data(page):
    """ Get pagination for start loop. Get data json"""
    global pagination
    url = f'https://lalafo.kg/bishkek/kvartiry/prodazha-kvartir?sort_by=default&page={str(page)}'
    count = 0
    while count <= 2:
        with requests.Session() as session:
            try:
                response = session.get(url=url, headers=headers)
                time.sleep(randrange(1, 2))
                soup = BeautifulSoup(response.text, 'html.parser')
                data_str_like_json = soup.find('script', id="__NEXT_DATA__", type="application/json").text
                data_dict = json.loads(data_str_like_json)
                if page == 0:
                    pagination = int(data_dict['props']['initialState']['listing']['listingFeed']["_meta"]['pageCount'])
                    return pagination
                else:
                    return data_dict
            except Exception:
                print_ln(f'Error get data {url}', tab_type='', start_ln='\r',  end_ln='', color=Fore.RED)
            if count == 2:
                print_ln("Error has occurred. Please restart the script.", color=Fore.RED)
                beep(b_type=MB_ICONHAND)
                sys.exit()
            count += 1

def parser_json():
    """Scraping pages and save to xls file"""
    pre_id = 0
    for page in tqdm(range(1, get_pag_data(0) + 1), desc='Scraping pages', unit='page', ncols=MESS_LEN,
                     bar_format="{l_bar}%s{bar}%s{r_bar}" % (Fore.GREEN, Fore.RESET)):
        data_dict = get_pag_data(page)
        for key in data_dict['props']['initialState']['listing']['listingFeed']['items']:
            items_lists = [''] * len(header_items)
            items_lists[1] = key['id']
            items_lists[2] = 'https://lalafo.kg' + key['url']
            try:
                items_lists[3] = "tel:" + key['mobile']
            except:
                items_lists[3] = ''
            try:
                items_lists[4] = "tel:" + key['user']['business']['features']['contact_phones']['model']['contacts'][0][
                    'phone']
            except:
                items_lists[4] = ''
            try:
                items_lists[5] = "tel:" + key['user']['business']['features']['contact_phones']['model']['contacts'][1][
                    'phone']
            except:
                items_lists[5] = ''
            try:
                items_lists[6] = "tel:" + key['user']['business']['features']['contact_phones']['model']['contacts'][2][
                    'phone']
            except:
                items_lists[6] = ''
            try:
                items_lists[7] = "tel:" + key['user']['business']['features']['contact_phones']['model']['contacts'][3][
                    'phone']
            except:
                items_lists[7] = ''
            items_lists[8] = key['title']
            try:
                items_lists[9] = key['price']
                items_lists[10] = key['currency']
            except:
                items_lists[9] = ''
                items_lists[10] = ''
            city_timezone = pytz.timezone("Asia/Bishkek")  # local_timezone = tzlocal.get_localzone()
            items_lists[11] = datetime.datetime.fromtimestamp(
                key['created_time'], city_timezone).strftime('%Y-%m-%d %H:%M')
            items_lists[12] = datetime.datetime.fromtimestamp(
                key['updated_time'], city_timezone).strftime('%Y-%m-%d %H:%M')
            if pre_id != key['id']:
                pre_id = key['id']
            items_dict[key['id']] = items_lists

    for num, key in enumerate(items_dict):
        items_dict[key][0] = num + 1
    print_ln(f'Quantity of parsed items: ', start_ln='', tab_type='', end_ln='', color=Fore.GREEN)
    print_ln(f'{len(items_dict)}', start_ln='', tab_type='')  # color = Fore.WHITE

def write_items_xlsx(name_xlsx, data_dict_, header_list_):
    """ write data to xlsx file"""
    work_book_ = Workbook()
    work_cell = work_book_.active
    work_cell.column_dimensions['A'].width = len(header_list_[0])
    work_cell.column_dimensions['B'].width = len(header_list_[1]) + 5
    work_cell.column_dimensions['C'].width = len(header_list_[2]) + 7
    work_cell.column_dimensions['D'].width = len(header_list_[3]) + 3
    work_cell.column_dimensions['E'].width = len(header_list_[4]) + 2
    work_cell.column_dimensions['F'].width = len(header_list_[5]) + 2
    work_cell.column_dimensions['G'].width = len(header_list_[6]) + 2
    work_cell.column_dimensions['H'].width = len(header_list_[7]) + 2
    work_cell.column_dimensions['I'].width = len(header_list_[8]) + 12
    work_cell.column_dimensions['J'].width = len(header_list_[9]) + 2
    work_cell.column_dimensions['K'].width = len(header_list_[10])
    work_cell.column_dimensions['L'].width = len(header_list_[11]) + 4
    work_cell.column_dimensions['M'].width = len(header_list_[12]) + 4
    work_cell.title = f'lalafo_kg_{len(data_dict_)}itm_{current_data}'
    if header_list_ != "":
        work_cell.append(header_list_)
    if len(data_dict_) != 0:
        for row in data_dict_.values():
            work_cell.append(row)
        for cell in work_cell["1:1"]:
            cell.font = Font(bold=True)
        work_book_.save(name_xlsx)
    else:
        print_ln('Noting to write. Data is empty', start_ln='', tab_type='*', color=Fore.GREEN)

def print_ln(message, tab_type='…', start_ln='\n', end_ln='\n', color=Fore.WHITE):
    """ Print messages in line"""
    mess_len = MESS_LEN
    if len(tab_type) == 0:
        spc = ""
    else:
        spc = " "
    tab_len = int((mess_len - 2 - len(message)) / 2)
    print(color + start_ln + tab_type * tab_len + spc + message + spc + " " * (
            len(message) % 2) + tab_type * tab_len, end=end_ln)

def beep(times=1, b_type=MB_OK):
    """Sound notifications"""
    for _ in range(times):
        MessageBeep(b_type)
        time.sleep(1)

def main():
    """Run parser"""
    cursor.hide()

    print_ln("lalafo_kg parser's started", color=Fore.GREEN)
    parser_json()
    xlsx_pathname = 'lalafo_kg_' + str(len(items_dict)) + 'items_' + current_data_time + '.xlsx'
    write_items_xlsx(xlsx_pathname, items_dict, header_items)
    print_ln('End', start_ln='', color=Fore.GREEN)
    beep(3)
    os.startfile(abspath_workdir)
    os.startfile(xlsx_pathname)
    cursor.show()

if __name__ == '__main__':
    main()


import unittest

import opentimelineio as otio
import opentimelineio.test_utils as otio_test_utils

class EffectTest(unittest.TestCase, otio_test_utils.OTIOAssertions):

    def test_cons(self):
        ef = otio.schema.Effect(
            name="blur it",
            effect_name="blur",
            metadata={"foo": "bar"}
        )
        encoded = otio.adapters.otio_json.write_to_string(ef)
        decoded = otio.adapters.otio_json.read_from_string(encoded)
        self.assertIsOTIOEquivalentTo(ef, decoded)
        self.assertEqual(decoded.name, "blur it")
        self.assertEqual(decoded.effect_name, "blur")
        self.assertEqual(decoded.metadata['foo'], 'bar')

    def test_eq(self):
        ef = otio.schema.Effect(
            name="blur it",
            effect_name="blur",
            metadata={"foo": "bar"}
        )
        ef2 = otio.schema.Effect(
            name="blur it",
            effect_name="blur",
            metadata={"foo": "bar"}
        )
        self.assertIsOTIOEquivalentTo(ef, ef2)

    def test_str(self):
        ef = otio.schema.Effect(
            name="blur it",
            effect_name="blur",
            metadata={"foo": "bar"}
        )
        self.assertMultiLineEqual(
            str(ef),
            "Effect({}, {}, {})".format(
                str(ef.name),
                str(ef.effect_name),
                str(ef.metadata)
            )
        )
        self.assertMultiLineEqual(
            repr(ef),
            "otio.schema.Effect("
            "name={}, "
            "effect_name={}, "
            "metadata={}"
            ")".format(
                repr(ef.name),
                repr(ef.effect_name),
                repr(ef.metadata),
            )
        )

    def test_setters(self):
        ef = otio.schema.Effect(
            name="blur it",
            effect_name="blur",
            metadata={"foo": "bar"}
        )
        self.assertEqual(ef.effect_name, "blur")
        ef.effect_name = "flop"
        self.assertEqual(ef.effect_name, "flop")

class TestLinearTimeWarp(unittest.TestCase, otio_test_utils.OTIOAssertions):
    def test_cons(self):
        ef = otio.schema.LinearTimeWarp("Foo", 2.5, {'foo': 'bar'})
        self.assertEqual(ef.effect_name, "LinearTimeWarp")
        self.assertEqual(ef.name, "Foo")
        self.assertEqual(ef.time_scalar, 2.5)
        self.assertEqual(ef.metadata, {"foo": "bar"})

    def test_serialize(self):
        ef = otio.schema.LinearTimeWarp("Foo", 2.5, {'foo': 'bar'})
        encoded = otio.adapters.otio_json.write_to_string(ef)
        decoded = otio.adapters.otio_json.read_from_string(encoded)
        self.assertIsOTIOEquivalentTo(ef, decoded)

    def test_setters(self):
        ef = otio.schema.LinearTimeWarp("Foo", 2.5, {'foo': 'bar'})
        self.assertEqual(ef.time_scalar, 2.5)
        ef.time_scalar = 5.0
        self.assertEqual(ef.time_scalar, 5.0)

class TestFreezeFrame(unittest.TestCase):
    def test_cons(self):
        ef = otio.schema.FreezeFrame("Foo", {'foo': 'bar'})
        self.assertEqual(ef.effect_name, "FreezeFrame")
        self.assertEqual(ef.name, "Foo")
        self.assertEqual(ef.time_scalar, 0)
        self.assertEqual(ef.metadata, {"foo": "bar"})

if __name__ == '__main__':
    unittest.main()


# -*- coding: utf-8 -*-
"""
Created on Tue Jan  9 08:12:25 2018

@author: Andrew
"""

import sqlite3

import numpy as np
#Even though the library is referenced as cv2,
import cv2 as cv

import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from PIL import Image
from PIL import ImageTk

from functools import partial

import os
import datetime
import pickle
import hashlib

import random
import time
from sklearn import svm
# http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame

class VerticalScrolledFrame(tk.Frame):
    """A pure Tkinter scrollable frame that actually works!
    * Use the 'interior' attribute to place widgets inside the scrollable frame
    * Construct and pack/place/grid normally
    * This frame only allows vertical scrolling

    """
    def __init__(self, parent, *args, **kw):
        tk.Frame.__init__(self, parent, *args, **kw)

        # create a canvas object and a vertical scrollbar for scrolling it
        vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
        vscrollbar.pack(fill=tk.Y, side=tk.RIGHT, expand=tk.FALSE)
        canvas = tk.Canvas(self, bd=0, highlightthickness=0,
                        yscrollcommand=vscrollbar.set)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.TRUE)
        vscrollbar.config(command=canvas.yview)

        # reset the view
        canvas.xview_moveto(0)
        canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = interior = tk.Frame(canvas)
        interior_id = canvas.create_window(0, 0, window=interior,
                                           anchor=tk.NW)

        # track changes to the canvas and frame width and sync them,
        # also updating the scrollbar
        def _configure_interior(event):
            # update the scrollbars to match the size of the inner frame
            size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
            canvas.config(scrollregion="0 0 %s %s" % size)
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the canvas's width to fit the inner frame
                canvas.config(width=interior.winfo_reqwidth())
        interior.bind('<Configure>', _configure_interior)

        def _configure_canvas(event):
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the inner frame's width to fill the canvas
                canvas.itemconfigure(interior_id, width=canvas.winfo_width())
        canvas.bind('<Configure>', _configure_canvas)

class Application:

    class ImageData:
        def __init__(self, ID, image, timestamp, contains_human):
            '''
            Default constructor, should not be used outside the ImageData class.
            '''
            self.ID = ID
            self.image = image
            self.timestamp = timestamp
            self.contains_human = contains_human

        @classmethod
        def from_file(cls, path, contains_human=0):
            '''
            Given a specified file path, instantiates an ImageData object.

            By default, the image does not contain a human.  All other fields
            are derived from the image file itself.

            This function is intended to create an ImageData object for an image
            file.
            '''
            #read image using OpenCV
            image     = cv.imread(path)
            timestamp = cls.__get_timestamp(path)
            ID        = cls.__compute_hash(image)

            return cls(ID, image, timestamp, contains_human)

        @classmethod
        def from_database(cls, ID, serialized_image, timestamp, contains_human):
            '''
            Given the four fields for an ImageData object, instantiates
            and returns an object.

            This function is intended to create an ImageData object for an image
            retrieved from the Image Database
            '''
            return cls(ID, cls.__deserialize(serialized_image), timestamp, contains_human)

        def serialize(self):
            return pickle.dumps(self.image)
        @staticmethod
        def __deserialize(data):
            return pickle.loads(data)
        @staticmethod
        def __get_timestamp(path):
            time = os.path.getmtime(path)
            return datetime.datetime.fromtimestamp(time)
        def __compute_hash(image):
            img_hasher      = hashlib.sha1()
            img_hasher.update(image)
            return img_hasher.hexdigest()
        def update(self, contains_human):
            self.contains_human = contains_human

    class Database:
        def __init__(self):
            self.connection = None
            self.cursor = None
        def is_open(self):
            return self.connection is not None
        def get_file_timestamp(self, file_path):
            time = os.path.getmtime(file_path)
            return datetime.datetime.fromtimestamp(time)

        def open_database(self, name):
            self.connection = sqlite3.connect(name)
            self.cursor = self.connection.cursor()
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS images(
                    id TEXT PRIMARY KEY,
                    img BLOB NOT NULL,
                    time_stamp TIMESTAMP NOT NULL,
                    contains_human BOOLEAN NOT NULL)''')
        def close_database(self):
            if self.connection is None:
                return
            self.connection.close()
            self.connection = None
            self.cursor = None
        def add_image_from_path(self, path, contains_human=0):
            self.add_image(Application.ImageData.from_file(path, contains_human))
        def add_image(self, data):
            try:
                self.cursor.execute('''INSERT INTO images
                                    (id, img, time_stamp, contains_human)
                                    VALUES (?, ?, ?, ?);''',
                              [data.ID,
                               data.serialize(),
                               data.timestamp,
                               data.contains_human])
                self.connection.commit()
            except sqlite3.IntegrityError:
                self.update_image(data)
        def update_image(self, data):
            self.cursor.execute('''UPDATE images
                              SET contains_human = ?
                              WHERE id = ?;''',
                            (data.contains_human, data.ID))
            self.connection.commit()
        def delete_image(self, data):
            print("Deleting image of ID {}".format(data.ID))
            self.cursor.execute('''DELETE from
                                images
                                WHERE
                                id = '{}';'''.format(data.ID))
            self.connection.commit()
        def query_database(self, contains_human = None):
            conditions = []
            if contains_human is not None:
                conditions.append("(contains_human = {})".format(contains_human))
            query = '''SELECT *
            FROM images

            '''
            if len(conditions) > 0:
                query += 'WHERE '
                for c in conditions[:-1]:
                    query += c
                    query += ' AND '
                query += conditions[-1]
            query += ';'
            print('QUERY:')
            print(query)
            self.cursor.execute(query)
            images = []
            for i in self.cursor:
                images.append(Application.ImageData.from_database(i[0], i[1], i[2], i[3]))
            return images
        def dump_all_images(self):
            self.cursor.execute('''SELECT img FROM images;''')
            images = []
            for i in self.cursor:
                image  = Application.ImageData.from_database(i[0], i[1], i[2], i[3])
                images.append(image.image)
            for i in range(1, len(images) + 1):
                cv.imwrite('OUTPUT/IMGDUMP - {}.png'.format(i), images[i-1])

    class AdminInterface:
        '''
        Provides a Graphical User Interface for the System Administrator.

        The System Administrator is not necessarily a priviliged user, but
        rather a user with a different role from the System Monitor.  This
        user could just as appropriately be referred to as "System Maintenance"
        '''
        def __init__(self):
            self.model = None

            '''
            Initializes the "Admin" Panel.
            '''
            def on_close(this):
                this.root.destroy()
                if this.database is not None:
                    this.database.close_database()
            self.database = Application.Database()
            self.root  = tk.Tk()
            self.toplevel = tk.LabelFrame(master=self.root,
                                     text  = 'Main Panel',
                                     padx  = 5,
                                     pady  = 5)
            self.toplevel.pack(side = tk.TOP)
            info_frame = tk.LabelFrame(master = self.toplevel,
                                     text  = 'Information')
            info_frame.pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            tk.Label(master = info_frame,
                     text = 'Mrs. Drone - Administration System').pack(side = tk.TOP, expand = 1, fill = tk.X)
            tk.Label(master = info_frame,
                     text = 'Version: Beta 0.2').pack(side = tk.TOP, expand = 1, fill = tk.X)
            self.database_label = tk.StringVar(master = info_frame,
                                               value = 'N/A')
            tk.Label(master = info_frame,
                     textvariable = self.database_label).pack(side = tk.TOP, expand = 1, fill = tk.X)
            button_panel = tk.LabelFrame(master = self.toplevel,
                                     text  = 'Controls',
                                     padx  = 5,
                                     pady  = 5)
            button_panel.pack(side = tk.LEFT, expand = 1, fill = tk.X)
            button_args = [('New Database', self.__new_database_dialog),
                           ('Open Database', self.__open_database_dialog),
                           ('Add Images', self.__add_images_dialog),
                           ('Query Database', self.__query_database_window),
                           ('Train Model', self.__build_model),
                           ('Exit', partial(on_close, self))]
            self.top_level_commands = []
            for b in button_args:
                self.top_level_commands.append(tk.Button(master = button_panel,
                          text   = b[0],
                          command= b[1]))
                self.top_level_commands[-1].pack(side = tk.TOP, expand = 1, fill = tk.X)
            self.action_frame = None
            self.__init_action_frame()
            self.image_frame = None
            self.__init_image_frame()

            tk.mainloop()
        #Did not use a semaphore here because this is more about showing the user
        #which commands are available, rather than controlling timing with the system.
        def __lock_top_level_commands(self):
            for c in self.top_level_commands:
                c.config(state=tk.DISABLED)
        def __unlock_top_level_commands(self):
            for c in self.top_level_commands:
                c.config(state=tk.NORMAL)
        def __init_action_frame(self, text = "None"):
            if self.action_frame is not None:
                self.action_frame.destroy()
            self.action_frame = tk.LabelFrame(master=self.toplevel,
                                              text  = "Current Action - {}".format(text),
                                              padx  = 5,
                                              pady  = 5)
            self.action_frame.pack(side = tk.RIGHT, expand = 1, fill = tk.BOTH)
        def __init_image_frame(self, text = "None"):
            if self.image_frame is not None:
                self.image_frame.destroy()
            self.image_frame = tk.LabelFrame(master=self.root,
                                              text  = "Image Manipulation Frame".format(text),
                                              padx  = 5,
                                              pady  = 5)
            self.image_frame.pack(expand = 1, fill = tk.BOTH)
            self.image_view = VerticalScrolledFrame(parent=self.image_frame)
            self.image_view.pack(expand = 1, fill = tk.BOTH)
        def __new_database_dialog(self):
            options = {}
            options['defaultextension'] = '.sqlite3'
            options['filetypes'] = [('SQLite3 Database', '.sqlite3')]
            options['initialfile']      = 'new.sqlite3'
            options['title']            = 'New Database'
            path = filedialog.asksaveasfilename(**options)
            if len(path) > 0 and not os.path.exists(path):
                self.database_label.set(path)
                return self.database.open_database(path)
            return None
        def __open_database_dialog(self):
            options = {}
            options['defaultextension'] = '.sqlite3'
            options['filetypes'] = [('SQLite3 Database', '.sqlite3')]
            options['title']            = 'Open Database'
            path = filedialog.askopenfilename(**options)
            if len(path) > 0:
                self.database_label.set(path)
                return self.database.open_database(path)
            return None
        def __add_images_dialog(self):
            if not self.database.is_open():
                return
            self.__init_action_frame(text = "Add Images to the Database")
            master = self.action_frame
            def on_close():
                self.__init_action_frame()
                self.__unlock_top_level_commands()
            def select_images(mode):
                if len(mode.curselection()) == 0:
                    return
                mode = mode.curselection()[0]
                options = {}
                options['defaultextension'] = '.sqlite3'
                options['title']            = 'Open Database'
                options['filetypes']        = [('FORMAT', '.jpg')]
                paths = filedialog.askopenfilenames(**options)
                on_close()
                print(mode)
                total = len(paths) + 1
                i = 1
                if mode == 0:
                    for p in paths:
                        print('Adding image {} of {}.'.format(i, total))
                        i += 1
                        img = Application.ImageData.from_file(path=p, contains_human=1)
                        self.__update_database(img, 1)
                elif mode == 1:
                    for p in paths:
                        print('Adding image {} of {}.'.format(i, total))
                        i += 1
                        img = Application.ImageData.from_file(path=p, contains_human=0)
                        self.__update_database(img, 0)
                else:
                    for p in paths:
                        img = Application.ImageData.from_file(path=p)
                        self.__edit_image_window(img, master=master)

            mode = tk.Listbox(master = master,
                              selectmode=tk.SINGLE)
            mode.insert(0,
                        'Images contain a human',
                        'Images do not contain humans',
                        'Ask whether each image contains a human')
            mode.config(width=0)
            mode.pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            tk.Button(master = master,
                      text = 'Select images',
                      command = partial(select_images,
                                        mode)).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            tk.Button(master = master,
                      text = 'Cancel',
                      command = on_close).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            self.__lock_top_level_commands()
        def __update_database(self, data, contains_human):
            data.update(contains_human)
            self.database.cursor.execute('''SELECT * FROM images WHERE id = "{}"'''.format(data.ID))
            if self.database.cursor.fetchone() is not None:
                self.database.update_image(data)
            else:
                self.database.add_image(data)
        def __delete_image(self, data):
            self.database.delete_image(data)
        def __query_database(self, contains_human_widget=None):
            if contains_human_widget is not None:
                contains_human_options = {0 : 1,
                                      1 : 0,
                                      2 : None}
                human = contains_human_options[contains_human_widget.curselection()[0]]
            else:
                human = None
            result = self.database.query_database(
                    contains_human = human)
            self.__init_image_frame()
            self.query = {}
            def delete_callback(f, image):
                self.__delete_image(image)
                f.destroy()
            def update_callback(image, contains_human):
                image.contains_human = contains_human
                self.__update_database(image, contains_human)
                if image.contains_human:
                    self.query[image.ID]['contains_human_var'].set('Contains a human.')
                else:
                    self.query[image.ID]['contains_human_var'].set('Does not contain a human.')
            for image in result:
                f = tk.Frame(master = self.image_view.interior)
                f.data = image
                f.pack(side = tk.TOP)
                self.query[image.ID] = {'frame' : f,
                          'timestamp'           : image.timestamp,
                          'contains_human_var'  : tk.StringVar(master=f)}
                if image.contains_human:
                    self.query[image.ID]['contains_human_var'].set('Contains a human.')
                else:
                    self.query[image.ID]['contains_human_var'].set('Does not contain a human.')
                b,g,r = cv.split(image.image)
                tk_image = ImageTk.PhotoImage(Image.fromarray(cv.merge((r,g,b))))
                label = tk.Label(master = f, image = tk_image)
                label.image = tk_image
                label.pack(side = tk.LEFT)
                controls = tk.Frame(master = f)
                controls.pack(side=tk.RIGHT, expand=1, fill=tk.BOTH)
                tk.Label(master = controls, text = 'ID - {}'.format(image.ID)).pack(side=tk.TOP)
                tk.Label(master = controls, text = 'Timestamp - {}'.format(image.timestamp)).pack(side=tk.TOP)
                tk.Label(master = controls,
                         textvariable = self.query[image.ID]['contains_human_var']).pack(side=tk.TOP)
                tk.Button(master=controls,
                          text = 'SET - Image contains a human',
                          command = partial(update_callback, f.data, 1)).pack(side = tk.TOP, expand = 1, fill = tk.X)
                tk.Button(master=controls,
                          text = 'SET - Image does not contain a human',
                          command = partial(update_callback, f.data, 0)).pack(side = tk.TOP, expand = 1, fill = tk.X)
                tk.Button(master=controls,
                          text = 'Delete',
                          command = partial(delete_callback, f, image)).pack(side = tk.TOP, expand = 1, fill = tk.X)
                tk.Button(master=controls,
                          text = 'Dismiss',
                          command = partial(f.destroy)).pack(side = tk.TOP, expand = 1, fill = tk.X)
        def __query_database_window(self):
            if not self.database.is_open():
                return
            self.__init_action_frame(text = "Query Database")
            master = self.action_frame
            def on_close():
                self.__init_action_frame()
                self.__init_image_frame()
                self.__unlock_top_level_commands()
            def select_all():
                msg = '''Warning: Do not use the Select All operation on large databases.
                Are you sure you want to proceed?
                '''
                if not messagebox.askokcancel(title = 'Warning', message = msg, icon = tk.messagebox.WARNING):
                    return
                print('getting results')
                self.__query_database()
            controls = tk.LabelFrame(master = master,
                                     text   = 'Controls',
                                     padx   = 5,
                                     pady   = 5)
            controls.pack(side = tk.TOP, expand = 1, fill = tk.X)
            contains_human_frame = tk.Frame(master = controls)
            contains_human_frame.pack(side = tk.LEFT)
            contains_human = tk.Listbox(master = controls,
                              selectmode=tk.SINGLE)
            contains_human.insert(0,
                        'Retrieve only images which contain humans.',
                        'Retrieve only images which do not contain humans.',
                        'Retrieve images regardless of whether they contain humans.')
            contains_human.config(width=0)
            contains_human.pack(side = tk.TOP)

            timestamp_frame = tk.LabelFrame(master = controls,
                                     text   = 'Image Timestamp Range',
                                     padx   = 5,
                                     pady   = 5)
            tk.Label(master = timestamp_frame,
                     text   = 'TODO - query database by timestamp range')

            tk.Button(master = controls,
                      text = "Retrieve All Images from Database",
                      command = select_all).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)

            tk.Button(master = controls,
                      text = "Retrieve Images which meet given criteria",
                      command = partial(self.__query_database,
                                        contains_human)).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)

            tk.Button(master = controls,
                      text = 'Exit',
                      command = on_close).pack(side = tk.RIGHT, expand = 1, fill = tk.BOTH)
            self.__lock_top_level_commands()
        def __edit_image_window(self, data, master=None):
            print("Called")
            #self.edit_image_window_sem.acquire(blocking=True)
            if master is None:
                master = self.root
            def on_close():
                popup.destroy()
                self.__init_image_frame()
                #self.edit_image_window_sem.release()
            #I'm sorry to anyone who has to read the code of this function...
            #TODO - Clean up this function to remove the need for a popup window, and also
            def on_confirm():
               self. __update_database(data, result.get())
               on_close()
            popup = tk.Toplevel(master = self.root)
            m = tk.PanedWindow(master = popup)
            m.pack(fill = tk.BOTH, expand = 1)

            b,g,r = cv.split(data.image)   #Credit - Iony at https://stackoverflow.com/questions/28670461/read-an-image-with-opencv-and-display-it-with-tkinter
            tk_image    = ImageTk.PhotoImage(Image.fromarray(cv.merge((r,g,b))))
            left        = tk.Label(m, image = tk_image)
            left.image  = tk_image
            left.pack()
            m.add(left)

            right       = tk.PanedWindow(m, orient = tk.VERTICAL)
            right.pack()

            hash_frame  = tk.PanedWindow(right, orient = tk.HORIZONTAL)
            hash_frame.pack()
            hash_frame1 = tk.Label(hash_frame, text = "Image ID: ")
            hash_frame2 = tk.Label(hash_frame, text = data.ID)
            hash_frame.add(hash_frame1)
            hash_frame.add(hash_frame2)

            right.add(hash_frame)

            time_frame  = tk.PanedWindow(right, orient = tk.HORIZONTAL)
            time_frame.pack()
            time_frame1 = tk.Label(time_frame, text = "Timestamp: ")
            time_frame2 = tk.Label(time_frame, text = data.timestamp)
            time_frame.add(time_frame1)
            time_frame.add(time_frame2)

            right.add(time_frame)

            bool_frame  = tk.PanedWindow(right, orient = tk.HORIZONTAL)
            bool_frame.pack()
            bool_frame1 = tk.Label(bool_frame, text = 'Image contains a human:')
            bool_frame2 = tk.PanedWindow(bool_frame, orient = tk.VERTICAL)
            bool_frame2.pack()
            result = tk.BooleanVar(bool_frame)
            has_human = tk.Radiobutton(master   = bool_frame2,
                                       text     = "Yes",
                                       variable = result,
                                       value = 1,
                                       state    = tk.NORMAL)
            no_human  = tk.Radiobutton(master   = bool_frame2,
                                       text     = "No",
                                       variable = result,
                                       value = 0,
                                       state    = tk.NORMAL)

            bool_frame2.add(has_human)
            bool_frame2.add(no_human)

            bool_frame.add(bool_frame1)
            bool_frame.add(bool_frame2)
            right.add(bool_frame)

            confirm_button = tk.Button(master  = right,
                                       text    = 'Confirm',
                                       command = on_confirm)
            right.add(confirm_button)
            m.add(right)
        def __build_model(self):
            self.__init_action_frame(text = "Calibration of SVM")
            master = self.action_frame
            def on_close():
                self.dataset = []
                self.dataset_diagnostic = 'N/A'
                self.__init_action_frame()
                self.__unlock_top_level_commands()
            def __open_databases():
                options = {}
                options['defaultextension'] = '.sqlite3'
                options['filetypes'] = [('SQLite3 Database', '.sqlite3')]
                options['title']            = 'Open Database'
                paths = filedialog.askopenfilenames(**options)
                self.dataset = []
                for p in paths:
                    db = Application.Database()
                    db.open_database(name = p)
                    self.dataset += db.query_database()
                pos = 0
                neg = 0
                for i in self.dataset:
                    if i.contains_human:
                        pos += 1
                    else:
                        neg += 1
                self.dataset_diagnostic.set('Total Dataset - {} Positive, {} Negative.'.format(
                        pos, neg))
                self.model = Application.HD_SVM([[d.image, d.contains_human] for d in self.dataset])
            info = tk.LabelFrame(master = master,
                                text   = 'Information',
                                padx   = 5,
                                pady   = 5)
            info.pack(side = tk.RIGHT, expand = 1, fill = tk.X)
            self.dataset_diagnostic = tk.StringVar(master = info,
                         value = 'Total Dataset - 0 Positive, 0 Negative.')
            tk.Label(master = info,
                     textvariable = self.dataset_diagnostic).pack(side = tk.RIGHT, expand = 1, fill = tk.X)
            controls = tk.LabelFrame(master = master,
                                text   = 'Controls',
                                padx   = 5,
                                pady   = 5)
            controls.pack(side = tk.LEFT, expand = 1, fill = tk.X)
            tk.Button(master = controls,
                      text = 'Load Database(s)',
                      command = __open_databases).pack(side = tk.TOP, expand = 1, fill = tk.BOTH)
            tk.Button(master = controls,
                      text = 'Exit',
                      command = on_close).pack(side = tk.BOTTOM, expand = 1, fill = tk.BOTH)
            self.__lock_top_level_commands()
    class HD_SVM:
        def __init__(self, dataset, seed = 42):
            self.X = [d[0] for d in dataset]
            self.y = [d[1] for d in dataset]
            self.seed = seed
            self.SVM = svm.SVC()
            self.hog = cv.HOGDescriptor()
            self.hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector())
            false_positives = []
            false_negatives = []
            true_positives = []
            true_negatives = []
            self.hits = []
            t_start = 0
            t_end = 0
            t_diff = 0
            import matplotlib.pyplot as plt
            for i in range(len(self.X)):
                t_start = time.time()
                rectangle = self.hog.detectMultiScale(self.X[i])[0]
                #rectangle = self.hog.detectMultiScale(self.X[i], winStride=(4,4), padding=(0, 0), scale=1.1)[0]
                t_end = time.time()
                t_diff = t_end - t_start
                print('Processing took {} milliseconds for resolution {}x{}.'.format(t_diff * 1000,
                      len(self.X[i]),
                      len(self.X[i][0])))
                answer = self.y[i]
                print('Result - {}; Expected - {}'.format(len(rectangle) != 0, answer))
                if len(rectangle) == 0 and answer == 0:
                    true_negatives.append(self.X[i])
                    continue
                elif len(rectangle) == 0 and answer == 1:
                    false_negatives.append(self.X[i])
                    continue
                elif answer == 0:
                    false_positives.append(self.X[i])
                else:
                    true_positives.append(self.X[i])
                rectangle = rectangle[0]
                self.hits.append(self.X[i].copy())
                cv.rectangle(self.hits[-1],
                             (rectangle[0], rectangle[1]),
                             (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3]),
                             (255, 0, 0))
            print('{} True Positives, {} True Negatives, {} False Positives, {} False Negatives.'.format(
                    len(true_positives), len(true_negatives), len(false_positives), len(false_negatives)))

    class MonitorInterface():
        def __init__(self, hits):
            cap = cv.VideoCapture(1)
            self.SVM = svm.SVC()
            self.hog = cv.HOGDescriptor()
            self.hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector())
            while(1):
                ret, frame = cap.read()
                #gray = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
                cv.imshow('Live Video Feed', frame)
                if cv.waitKey(1) & 0xFF == ord('q'):
                    break
                rectangle = self.hog.detectMultiScale(frame)[0]

                if len(rectangle) != 0:
                    rectangle = rectangle[0]
                    print('HUMAN DETECTED')
                    hits.append(frame.copy())
                    cv.rectangle(hits[-1],
                                 (rectangle[0], rectangle[1]),
                                 (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3]),
                                 (255, 0, 0))
                time.sleep(1)
            cap.release()
            cv.destroyAllWindows()
#x = Application.AdminInterface()
#y = Application.MonitorInterface()
def view(img):
    cv.imshow('image',img)
    cv.waitKey(0)
    cv.destroyAllWindows()

def t1():
    x = Application.AdminInterface()
def t2(hits):
    y = Application.MonitorInterface(hits)
import _thread
hits = []
def review():
    for img in hits:
        view(img)
x = _thread.start_new_thread(t2, (hits,))
#y = _thread.start_new_thread(t1, ())

'''
DEPRECATED, old main method from dbPrototype.bak

def main():
    db = open_database('blake.db')
    c = db.cursor()
    for image in os.listdir('INPUT'):
        add_img_from_path(c, 'INPUT/' + image)
        db.commit()
    db.close()

#if __name__ == '__main__': main()
'''


from modules import cbpi
from modules.core.props import Property
from modules.core.hardware import ActorBase
import requests
#import time

@cbpi.actor
class DefinedState(ActorBase):
    #custom property
    actordesc = "select an actor to control state"
    actor01 = Property.Actor("Actor 1", description=actordesc)
    actor01_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    actor02 = Property.Actor("Actor 2", description=actordesc)
    actor02_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    actor03 = Property.Actor("Actor 3", description=actordesc)
    actor03_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    actor04 = Property.Actor("Actor 4", description=actordesc)
    actor04_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    actor05 = Property.Actor("Actor 5", description=actordesc)
    actor05_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    actor06 = Property.Actor("Actor 6", description=actordesc)
    actor06_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    actor07 = Property.Actor("Actor 7", description=actordesc)
    actor07_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    actor08 = Property.Actor("Actor 8", description=actordesc)
    actor08_On_Off = Property.Select("On or OFF", options = ["On","Off"], description = "On or Off")
    #ta_stop  = Property.Number("Pause Timer", configurable=True, description="Defines how long the Agitator should stop before run again.")

    def init(self):
        self.actors = []
        self.YesNo = []

        if isinstance(self.actor01, unicode) and self.actor01:
            self.actors.append(int(self.actor01))
            self.YesNo.append(self.actor01_On_Off)
        if isinstance(self.actor02, unicode) and self.actor02:
            self.actors.append(int(self.actor02))
            self.YesNo.append(self.actor02_On_Off)
        if isinstance(self.actor03, unicode) and self.actor03:
            self.actors.append(int(self.actor03))
            self.YesNo.append(self.actor03_On_Off)
        if isinstance(self.actor04, unicode) and self.actor04:
            self.actors.append(int(self.actor04))
            self.YesNo.append(self.actor04_On_Off)
        if isinstance(self.actor05, unicode) and self.actor05:
            self.actors.append(int(self.actor05))
            self.YesNo.append(self.actor05_On_Off)
        if isinstance(self.actor06, unicode) and self.actor06:
            self.actors.append(int(self.actor06))
            self.YesNo.append(self.actor06_On_Off)
        if isinstance(self.actor07, unicode) and self.actor07:
            self.actors.append(int(self.actor07))
            self.YesNo.append(self.actor07_On_Off)
        if isinstance(self.actor08, unicode) and self.actor08:
            self.actors.append(int(self.actor08))
            self.YesNo.append(self.actor08_On_Off)

    def set_power(self, power):
        for actor in self.actors:
            self.api.actor_power(actor, power=power)
	   #self.sleep(int(self.ta_stop))

    def on(self, power=None):
        i = 0
        for actor in self.actors:
            if self.YesNo[i] == "On":
                self.api.switch_actor_on(actor, power=power)
            else:
                self.api.switch_actor_off(actor)
            i = i+1
        #self.sleep(int(self.ta_stop))
        #self.api.cache.get("actors").get(int(self.id)).timer = int(time.time()) + int(self.ta_stop) -1
	#self.api.notify(headline="Timed Agitator", message="Timed Agitator started", type="info")

    def off(self):
        for actor in self.actors:
            self.api.switch_actor_off(actor)
        #self.sleep(int(self.ta_stop))