__all__ = ['HelpWdg', 'HelpContentWdg', 'HelpEditWdg', 'HelpEditCbk', 'HelpEditContentWdg','HelpDocFilterWdg']

import tacticenv

from pyasm.common import Environment, Xml, TacticException, Config, Common, Container
from pyasm.web import DivWdg, Table, SpanWdg, WebContainer
from pyasm.widget import TextAreaWdg, SelectWdg, HiddenWdg, IconWdg
from pyasm.search import Search, SearchType
from pyasm.command import Command

from tactic.ui.common import BaseRefreshWdg
from tactic.ui.widget import ActionButtonWdg, SingleButtonWdg, IconButtonWdg, ButtonNewWdg

import types, os
import re

__all__.append("HelpButtonWdg")
class HelpButtonWdg(BaseRefreshWdg):

    def init(self):
        self.cbjs_action = self.kwargs.get("cbjs_action")

    def add_style(self, key, value=None):
        self.top.add_style(key, value=value)

    def add_behavior(self, cbjs_action):
        self.cbjs_action = cbjs_action

    def exists():
        return Container.get("HelpWdg::exists") == True
    exists = staticmethod(exists)

    def get_display(self):

        top = self.top

        if not HelpWdg.exists():
            return top

        alias = self.kwargs.get("alias")
        description = self.kwargs.get("description")
        if not description:
            description = "Show Help"

        if self.kwargs.get("use_icon"):
            #help_button = SingleButtonWdg(title='Help', icon=IconWdg.HELP_BUTTON, show_arrow=False)
            help_button = ButtonNewWdg(title='Help', icon="FAR_QUESTION_CIRCLE", show_arrow=False)
        else:
            help_button = ActionButtonWdg(title="Help", tip=description, size='small', color="secondary")
        top.add(help_button)

        if not self.cbjs_action:
            self.cbjs_action = '''
            spt.help.set_top();
            spt.help.load_alias(bvr.alias);
            '''

            help_button.add_behavior( {
                'type': 'click_up',
                'alias': alias,
                'cbjs_action': self.cbjs_action
            } )

        return top

class HelpDocFilterWdg(BaseRefreshWdg):

    def get_display(self):

        alias = self.kwargs.get("alias")

        self.rel_path = self.kwargs.get("rel_path")
        if not self.rel_path:
            from tactic_client_lib import TacticServerStub
            server = TacticServerStub.get(protocol='local')
            self.rel_path = server.get_doc_link(alias)

        if not self.rel_path or self.rel_path == 'none_found':
            #raise TacticException("Help alias [%s] does not exist" % alias)
            layout = DivWdg()
            layout.add(HelpCreateWdg(alias=alias))
            layout.add(HelpDocFilterWdg(alias='main'))
            return layout

        # special condition for plugins path
        if self.rel_path.startswith("/plugins/"):
            plugin_dir = Environment.get_plugin_dir()
            rel_path = self.rel_path.replace("/plugins/", "")
            path = "%s/%s" % (plugin_dir,rel_path)
        elif self.rel_path.startswith("/builtin_plugins/"):
            plugin_dir = Environment.get_builtin_plugin_dir()
            rel_path = self.rel_path.replace("/builtin_plugins/", "")
            path = "%s/%s" % (plugin_dir,rel_path)
        elif self.rel_path.startswith("/assets/"):
            asset_dir = Environment.get_asset_dir()
            rel_path = self.rel_path.replace("/assets/", "")
            path = "%s/%s" % (asset_dir,rel_path)
        else:

            # see if there is an override
            doc_dir = os.environ.get("TACTIC_DOC_DIR")
            if not doc_dir:
                doc_dir = Config.get_value("install", "doc_dir")
            if not doc_dir:
                install_dir = Environment.get_install_dir()
                doc_dir = "%s/doc" % install_dir

            path = "%s/%s" % (doc_dir, self.rel_path)

        html = []
        try:
            paths = path.split('#')
            anchor = ''
            if len(paths) > 1:
                anchor = paths[-1]
                path = paths[0]
                read = False
            else:
                read = True

            f = open(path, 'r')
            count = 0
            idx = 0
            anchor_str = ''%anchor
            div_str = '
'
            strip_count = 0
            for line in f:
                if anchor and not read:
                    if not Common.IS_Pv3:
                        tmp_line = line.decode('utf-8', 'ignore')
                    else:
                        tmp_line = line
                    div_idx = tmp_line.find(div_str)
                    idx = tmp_line.find(anchor_str)
                    if idx != -1:
                        # use the div above the anchor
                        line = line[div_idx:-1]

                        # in case it doesn't get it right on
                        while strip_count < 30 and not line.startswith('
'):
                            line = line[1:-1]
                            strip_count +=  1

                        read = True

                if read:
                    line = self.filter_line(line, count)
                    html.append(line)
                    count += 1
            f.close()
        except Exception as e:
            print("Error processing: ", e)
            html.append("Error processing document: %s

" % str(e))
            raise

        html = "\n".join(html)
        if not html:
            html = "
"

        # let custom layout parse this first
        from tactic.ui.panel import CustomLayoutWdg
        rel_dir = os.path.dirname(self.rel_path)

        # TODO: this is only used to try to get images into plugin dogs
        # It breaks a lot of docs that have Mako examples
        #layout = CustomLayoutWdg(html=html, base_dir=rel_dir)
        #html = layout.get_buffer_display()

        try:
            tree = Xml.parse_html(html)
        except Exception as e:
            print("WARNING: ", e)
            # some crazy encoding for python 3.   Not sure why?
            #tree = Xml.parse_html(str(html.encode()))
            # Actually have to remove encode from html.  Just do a string replace
            # for now.
            html = html.replace('''encoding="UTF-8"''', '')
            tree = Xml.parse_html(html)

        xml = Xml(doc=tree)

        elements = self.filter_xml(xml)

        # generate the html
        top = self.top
        top.add_class("spt_help_top")
        top.add_style("min-width: 300px")
        top.add_style("min-height: 100px")
        top.add_color("background", "background")
        top.add_style("padding: 10px")
        top.add_style("font-size: 12px")
        top.add_class("spt_resizable")

        inner = DivWdg()
        top.add(inner)

        inner.add_behavior( {
            'type': 'load',
            'cbjs_action': '''
            var els = bvr.src_el.getElements(".spt_replace_element");
            for (var i = 0; i < els.length; i++) {
                var el = els[i];
                var replace_id = el.getAttribute("spt_replace_id");
                var el_old = document.id(replace_id);
                if (el_old) {
                    el.replaces(el_old);

                    var children = el_old.getChildren();
                    for (var j = 0; j < children.length; j++) {
                        el.appendChild(children[j]);
                    }
                }

            }
            '''
        } )

        inner.add_relay_behavior( {
            'type': 'mouseover',
            'bvr_match_class': 'spt_link',
            'cbjs_action': 'spt.mouse.table_layout_hover_over({}, {src_el: bvr.src_el, add_color_modifier: -5})'
        } )
        inner.add_relay_behavior( {
            'type': 'mouseout',
            'bvr_match_class': 'spt_link',
            'cbjs_action': 'spt.mouse.table_layout_hover_out({}, {src_el: bvr.src_el})'
        } )

        #node = xml.get_node("//body")
        #html = xml.to_string(node)
        ##print(html)
        #inner.add(html)

        nodes = xml.get_nodes("//body/*")
        for node in nodes:
            html = xml.to_string(node)

            html = html.replace("<", "&spt_lt;")
            html = html.replace(">", "&spt_gt;")
            inner.add(html)

        inner.add_behavior( {
            'type': 'load',
            'cbjs_action': '''
            var text = bvr.src_el.innerHTML;
            text = text.replace(/amp\;/g, "");
            spt.behavior.replace_inner_html(bvr.src_el, text);
            '''
        } )

        # add replacement html
        div = DivWdg()
        inner.add(div)
        div.add_class("spt_replacement")
        for element in elements:
            div.add(element)

        rel_path_div = DivWdg()
        rel_path_div.add("Source: %s" % self.rel_path)
        inner.add(rel_path_div)
        rel_path_div.add_style("opacity: 0.3")
        rel_path_div.add_style("margin-top: 10")

        if self.kwargs.get("is_refresh"):
            return inner
        else:
            return top

    def filter_line(self, line, count):
        '''replace certain tags with a replacement for proper display'''
        line = line.strip()
        if line.startswith("<meta"):
            line = line.replace(">", "/>")
        elif line.startswith("<link"):
            line = line.replace(">", "/>")
        elif line.find("<a ") != -1:
            import re
            p = re.compile("</>")
            p2 = re.compile("")
            line = re.sub(p, "", line)
            line = re.sub(p2, "", line)

        line = line.replace(" ", " ")
        line = line.replace("
", "
")
        line = line.replace("
", "
")
        return line

    def add_shadow(self, styles, value, color):
        browser = WebContainer.get_web().get_browser()
        if browser == 'Mozilla':
            styles.append("-moz-box-shadow: %s %s" % (value, color))
            styles.append("box-shadow: %s %s" % (value, color))
        elif browser == 'Webkit':
            styles.append("-webkit-box-shadow: %s %s" % (value, color))
            styles.append("box-shadow: %s %s" % (value, color))
        else:
            styles.append("box-shadow: %s %s" % (value, color))

    def filter_xml(self, xml):
        dirname = os.path.dirname(self.rel_path)

        # filter images
        img_nodes = xml.get_nodes("//img")
        install_dir = Environment.get_install_dir()
        for node in img_nodes:
            src = xml.get_attribute(node, "src")

            if src.startswith("/tactic/plugins/"):
                plugin_dir = Environment.get_plugin_dir()
                path = "%s/%s" % (plugin_dir, src.replace("/tactic/plugins/", "") )
            elif src.startswith("/tactic/builtin_plugins/"):
                plugin_dir = Environment.get_builtin_plugin_dir()
                path = "%s/%s" % (plugin_dir, src.replace("/tactic/builtin_plugins/", "") )

            elif src.startswith("/"):
                path = "%s/src%s" % (install_dir, src)
            else:
                path = "%s/doc/%s/%s" % (install_dir, dirname, src)

            size = (0,0)
            try:
                from PIL import Image
                im = Image.open(path)
                size = im.size
            except IOError as e:
                print("Error importing Image: ", e)

            except Exception as e:
                print("Error in opening image path:", path)
                print(e)
                #continue
                size = [0,0]

            style = xml.get_attribute(node, "style")
            if style:
                styles = style.split(";")
            else:
                styles = []

            shadow = DivWdg().get_color("shadow")
            if size[0] > 500:
                styles.append("width: 75%")
                styles.append("margin-left: 50px")
                styles.append("margin-bottom: 20px")
                styles.append("margin-top: 10px")
                self.add_shadow(styles, "0px 0px 15px", shadow)

            elif size[0] > 100:
                x = int(float(size[0])/500*75)
                styles.append("width: %s%%"%x)
                styles.append("margin-left: 50px")
                styles.append("margin-bottom: 20px")
                styles.append("margin-top: 10px")
                self.add_shadow(styles, "0px 0px 15px", shadow)

            else:
                self.add_shadow(styles, "0px 0px 15px", shadow)

            styles.append("border: solid 1px %s" % DivWdg().get_color("border"))
            style = ";".join(styles)
            xml.set_attribute(node, "style", style)

            if src.startswith("/"):
                new_src = src
            elif dirname:
                new_src = "/doc/%s/%s" % (dirname, src)
            else:
                new_src = "/doc/%s" % (src)

            #print("src: ", src)
            #print("new_src: ", new_src)
            #print("---")
            xml.set_attribute(node, "src", new_src)

        # filter links
        elements = []
        link_nodes = xml.get_nodes("//a")
        for node in link_nodes:

            href = xml.get_attribute(node, "href")

            if not href:
                # Test link to GitHub docs
                """
                # add a link to github
                github_node = xml.create_text_element("div", "edit >>")
                xml.insert_after(github_node, node)
                xml.set_attribute(github_node, "style", "float: right; font-size: 0.8em; opacity: 0.3")
                xml.set_attribute(github_node, "class", "hand")
                url = '''https://github.com/Southpaw-TACTIC/Docs/tree/master/section/doc/tactic-end-user/end-user/creating-tasks'''
                xml.set_attribute(github_node, "onclick", "window.open('%s', 'TACTIC Docs')" % url)
                """

                continue

            if dirname:
                link_rel_path = "%s/%s" % (dirname, href)
            else:
                link_rel_path = "%s" % (href)

            target = xml.get_attribute(node, "target")
            if target:
                target = xml.set_attribute(node, "href", "/doc/%s" % link_rel_path)
                continue

            # get a unique id for the node
            unique_id = self.top.generate_unique_id(base='replace')
            xml.set_attribute(node, "id", unique_id)

            div = SpanWdg()
            elements.append(div)
            div.add_class("spt_replace_element")
            div.add_attr("spt_replace_id", unique_id)
            div.add_class("hand")
            div.add_class("spt_link")
            div.add_color("background", "background")

            text = xml.get_node_value(node)
            div.add(text)
            div.add_behavior( {
                'type': 'click_up',
                'rel_path': link_rel_path,
                'cbjs_action': '''
                console.log("click link")
                spt.help.set_top();
                spt.help.load_rel_path( bvr.rel_path );
                '''
            } )

        # dummy div to get color
        div = DivWdg()

        # convert pre-elements to have < and >
        pre_nodes = xml.get_nodes("//pre")
        for node in pre_nodes:
            html = xml.to_string(node)
            html = re.sub(r'''
''','', html)
            html = html.replace('''
''','')
            if not html:
                continue

            styles = []
            styles.append("padding: 10px")
            styles.append("margin: 10px")
            styles.append("border: solid 1px %s" % div.get_color("border"))
            styles.append("background: %s" % div.get_color("background", -3))
            styles.append("color: %s" % div.get_color("color"))
            style = ";".join(styles)
            xml.set_attribute(node, "style", style)
            node.text = html

        # style the table nodes
        table_nodes = xml.get_nodes("//table")
        for node in table_nodes:
            styles = []
            #styles.append("border: solid 1px %s" % div.get_color("border"))
            styles.append("background: %s" % div.get_color("background", -1))
            style = ";".join(styles)
            xml.set_attribute(node, "style", style)
            xml.set_attribute(node, "cellpadding", "10")
            xml.set_attribute(node, "cellspacing", "0")
            xml.set_attribute(node, "border", "0")

        return elements

class HelpWdg(BaseRefreshWdg):

    def init(self):
        Container.put("HelpWdg::exists", True)
        self.show_add_new = self.kwargs.get('show_add_new') not in  ['false', False]

    def exists():
        return Container.get("HelpWdg::exists") == True
    exists = staticmethod(exists)

    def get_display(self):

        top = self.top

        #help_div = DivWdg()
        help_div = top
        #top.add(help_div)
        help_div.add_class("spt_help_top")
        help_div.set_id("spt_help_top")

        show_title = self.kwargs.get("show_title")
        if show_title in [True, 'true']:
            show_title = True
        else:
            show_title = False

        if show_title:
            title_wdg = DivWdg()
            help_div.add(title_wdg)
            title_wdg.add_style("font-size: 12px")
            title_wdg.add_style("font-weight: bold")
            title_wdg.add_color("background", "background", -10)
            title_wdg.add_style("padding: 3px")
            #title_wdg.add_style("margin-top: 8px")
            title_wdg.add_style("margin-bottom: 5px")
            title_wdg.add_style("height: 26px")
            title_wdg.add_style("padding: 6 0 0 6")
            title_wdg.set_round_corners(corners=['TL','TR'])

            icon = IconWdg("Close", IconWdg.KILL)
            title_wdg.add(icon)
            icon.add_style("float: right")
            title_wdg.add("Help")

        help_div.set_round_corners()
        help_div.add_color("color", "color2")
        help_div.add_color("background", "background")
        help_div.add_style("overflow: hidden")
        help_div.add_border()

        shelf_div = DivWdg()
        help_div.add(shelf_div)
        shelf_div.add_style("padding: 10px")
        shelf_div.add_color("background", "background", -10)
        shelf_div.add_style("height: 25px")

        #button = SingleButtonWdg(title="Documentation Main Page", icon=IconWdg.HOME)
        button = IconButtonWdg(title="Documentation Main Page", icon="BS_HOME")
        shelf_div.add(button)
        button.add_style("float: left")
        button.add_style("margin: 0px 10px")
        button.add_behavior( {
        'type': 'click_up',
        'cbjs_action': '''
        spt.help.set_top();
        spt.help.load_alias("main")
        '''
        } )

        #button = SingleButtonWdg(title="Edit Help", icon=IconWdg.EDIT)
        if self.show_add_new:
            button = IconButtonWdg(title="Add New Help", icon="FA_EDIT")
            shelf_div.add(button)
            button.add_style("float: left")
            button.add_style("margin: 0px 10px")
            button.add_behavior( {
            'type': 'click_up',
            'cbjs_action': '''
            spt.tab.set_main_body_tab();
            var class_name = 'tactic.ui.app.HelpEditWdg';

            var element_name = spt.help.get_view();
            if (!element_name) {
              element_name = "default";
            }
            var kwargs = {
              view: element_name
            }

            spt.tab.add_new("help_edit", "Help Edit", class_name, kwargs);

            '''
            } )

        #button = SingleButtonWdg(title="Go Back One Page", icon=IconWdg.ARROW_LEFT)
        button = IconButtonWdg(title="Go Back One Page", icon="BS_CIRCLE_ARROW_LEFT")
        shelf_div.add(button)
        button.add_style("float: left")
        button.add_style("margin: 0px 10px")
        button.add_behavior( {
        'type': 'click_up',
        'cbjs_action': '''
        spt.help.set_top();
        spt.help.load_prev();
        '''
        } )

        #button = SingleButtonWdg(title="Go Forward One Page", icon=IconWdg.ARROW_RIGHT)
        button = IconButtonWdg(title="Go Forward One Page", icon="BS_CIRCLE_ARROW_RIGHT")
        shelf_div.add(button)
        button.add_style("float: left")
        button.add_style("margin: 0px 10px")
        button.add_behavior( {
        'type': 'click_up',
        'cbjs_action': '''
        spt.help.set_top();
        spt.help.load_next();
        '''
        } )

        #button = SingleButtonWdg(title="Documentation Downloads", icon=IconWdg.DOWNLOAD)
        button = IconButtonWdg(title="Documentation Downloads", icon="BS_DOWNLOAD")
        shelf_div.add(button)
        button.add_style("float: right")
        button.add_behavior( {
        'type': 'click_up',
        'cbjs_action': '''
        spt.help.set_top();
        spt.help.load_alias("pdf")
        '''
        } )

        shelf_div.add("
")

        help_div.add_behavior( {
        'type': 'load',
        'cbjs_action': self.get_onload_js()
        })

        help_div.add_behavior( {
        'type': 'listen',
        'event_name': 'tab|select',
        'cbjs_action': '''

        var content = bvr.src_el.getElement(".spt_help_content");
        var options = bvr.firing_data;
        var element_name = options.element_name;
        var alias = options.alias;

        if (!alias) {
            alias = options.element_name;
        }

        spt.help.set_top();
        if (spt.help.is_visible()) {
            spt.help.load_alias(alias);
        }
        else {
            spt.help.set_view(alias);
        }
        '''

        } )

        help_div.add_behavior( {
        'type': 'listen',
        'event_name': 'show_help',
        'cbjs_action': '''
        var top = bvr.src_el.getParent(".spt_help");
        var content = top.getElement(".spt_help_content");
        var firing_data = bvr.firing_data;
        var class_name = firing_data.class_name;
        if (!class_name) {
            class_name = 'tactic.ui.app.HelpContentWdg';
        }

        if (top.getStyle("display") != 'none') {
            spt.hide(top);
            return;
        }

        spt.help.set_top()

        // get the help view
        var help_view = spt.help.get_view();
        var html = firing_data.html;
        if (html) {
            spt.help.load_html(html);
        }
        else {
            if (!help_view) {
                help_view = 'default'
            }
            spt.help.load_alias(help_view);
        }

        var size = document.id(window).getSize();

        var dialog = bvr.src_el.getParent(".spt_dialog_content");

        dialog.setStyle("height", size.y - 100);
        dialog.setStyle("width", 650);

        var top = bvr.src_el.getParent(".spt_dialog_top");
        top.setStyle("left", size.x - 660);
        top.setStyle("top", 40);

        spt.show(top);
        '''
        } )

        content = DivWdg()
        help_div.add(content)
        content.add_class("spt_help_content");
        content.add_style("position: relative")
        content.add_style("overflow_x: auto")
        content.add_style("overflow_y: auto")
        content.add_style("margin-bottom: 10px")
        #content.add_style("border: solid 1px blue")
        content.add_style("height: 98%")

        #key = "schema_editor"
        #search = Search("config/doc")
        #search.add_filter("code", key)
        #doc = search.get_sobject()
        #doc_html = doc.get_value("doc")
        #help_div.add(doc_html)

        return top

    def get_onload_js(self):
        return '''

if (spt.help) {
    return;
}

spt.Environment.get().add_library("spt_help");

spt.help = {};
spt.help.top = null;
spt.help.content = null;

spt.help.history = [['alias', 'main']];
spt.help.history_index = -1;

spt.help.current_view = null;

spt.help.set_view = function(view) {
    spt.help.current_view = view;
}

spt.help.get_view = function() {
    return spt.help.current_view;
}

// DEPRECATED
spt.help.show_help = function() {
    spt.named_events.fire_event("show_help", {} );
}

spt.help.show = function() {
    var container = spt.help.top.getParent(".spt_help");
    spt.show(container);
}

spt.help.hide = function() {
    var container = spt.help.top.getParent(".spt_help");
    spt.hide(container);
}

spt.help.is_visible = function() {
    var container = spt.help.top.getParent(".spt_help");
    if (container.getStyle("display") == "none") {
        return false;
    }
    else {
        return true;
    }
}

spt.help.set_top = function(el) {
    if (typeof(el) == 'undefined') {
        el = document.id("spt_help_top");
        spt.help.top = el;
    }

    if (el.hasClass("spt_help_top")) {
        spt.help.top = el;
    }
    else {
        spt.help.top = el.getParent(".spt_help_top");
    }

    spt.help.content = el.getElement(".spt_help_content");
}

spt.help.load_prev = function() {

    if (spt.help.history_index == 0) {
        spt.alert("No more pages to load");
        return;
    }

    if (spt.help.history_index == -1) {
        spt.help.history_index = spt.help.history.length - 2;
    }
    else {
        spt.help.history_index -= 1;
    }

    var info = spt.help.history[spt.help.history_index];
    var type = info[0];
    var value = info[1];
    if (type == 'alias') {
        spt.help.load_alias(value, false);
    }
    else {
        spt.help.load_rel_path(value, false);
    }
}

spt.help.load_next = function() {

    if (spt.help.history_index == -1) {
        spt.alert("No more pages to load");
        return;
    }

    if (spt.help.history_index == spt.help.history.length - 1) {
        spt.alert("No more pages to load");
        return;
    }
    else {
        spt.help.history_index += 1;
    }

    var info = spt.help.history[spt.help.history_index];
    var type = info[0];
    var value = info[1];
    if (type == 'alias') {
        spt.help.load_alias(value, false);
    }
    else {
        spt.help.load_rel_path(value, false);
    }
}

// let the server figure out what do do
spt.help.load_html = function(html) {

    if (!spt.help.is_visible() ) {
        spt.help.show();
    }

    var class_name = 'tactic.ui.app.HelpContentWdg';
    var kwargs = {
        view: 'view',
        html: html
    }

    var top = document.id("spt_help_top")
    if (!top) {
        spt.panel.load_popup("Help", class_name, kwargs, {width: "500px"});
    }
    else {
        spt.panel.load(top, class_name, args, {width: "500px"});
    }
}

// let the server figure out what do do
spt.help.load_alias = function(alias, history) {

    var class_name = 'tactic.ui.app.HelpContentWdg';
    var args = {
        alias: alias
    }

    if (!spt.help) return;

    spt.help.set_view(alias);

    var top = document.id("spt_help_top")
    if (!top) {
        var popup = spt.panel.load_popup("Help", class_name, args, {width: "600px"});
        var popup_content = popup.getElement(".spt_help_top");
    }
    else {
        spt.panel.load(top, class_name, args, {width: "500px"});
        var popup_content = top;

        var popup = top.getParent(".spt_popup");
        if (popup) {
            popup.setStyle("display", "");
            popup.setStyle("top", 0);
            popup.setStyle("right", 0);
            popup.setStyle("height", "100vh");
            popup.setStyle("max-width", "30%");
        }
    }

    spt.help.content = popup_content;

    if (typeof(history) == 'undefined') {
        history = true;
    }
    if (!history) {
        return;
    }

    if (spt.help.history_index != - 1) {
        spt.help.history = spt.help.history.slice(0, spt.help.history_index+1);
        spt.help.history_index = -1;
    }

    if (alias == spt.help.history[spt.help.history.length-1][1]) {
        return;
    }

    spt.help.history.push( ['alias', alias]);
}

spt.help.load_rel_path = function(rel_path, history) {

    var saved_path = rel_path;
    if (rel_path.indexOf("#") != -1) {
        var parts = rel_path.split("#");
        //rel_path can support anchor
        //rel_path = parts[0];
        tag = parts[1];
    }
    else {
        tag = null;
    }

    var class_name = 'tactic.ui.app.HelpContentWdg';
    var kwargs = {
        rel_path: rel_path
    }

    var top = document.id("spt_help_top")
    if (!top) {
        spt.panel.load_popup("Help", class_name, kwargs, {width: "500px"});
    }
    else {
        spt.panel.load(top, class_name, kwargs, {width: "500px"});
    }

    if (typeof(history) == 'undefined') {
        history = true;
    }
    if (!history) {
        return;
    }

    if (spt.help.history_index != - 1) {
        spt.help.history = spt.help.history.slice(0, spt.help.history_index+1);
        spt.help.history_index = -1;
    }

    if (rel_path == spt.help.history[spt.help.history.length-1][1]) {
        return;
    }

    spt.help.history.push( ['rel_path', saved_path]);
}

spt.help.load_custom = function(element_name) {
    var bvr = {};
    spt.help.set_view(element_name);
    bvr.options = {
      element_name: element_name,
    }
    spt.named_events.fire_event("show_help", bvr);
}

spt.help.set_top();
spt.help.set_view("main");

        '''

class HelpCreateWdg(BaseRefreshWdg):

    def get_display(self):
        alias = self.kwargs.get("alias")

        div = DivWdg()
        div.add_style("padding: 15px")
        div.add_style("margin: 10px")
        div.add_border()
        div.add_color("background", "background", -5)
        div.add_style("text-align: center")
        div.add_style("font-weight: bold")

        icon = IconWdg("WARNING", IconWdg.HELP_MISSING)
        div.add(icon)
        div.add("Add custom documentation page by clicking the Create button")

        from tactic.ui.widget import ActionButtonWdg
        button = ActionButtonWdg(title="Create", tip="Create docs for this view")
        div.add(button)
        button.add_style("margin-right: auto")
        button.add_style("margin-left: auto")
        button.add_style("margin-top: 15px")
        button.add_style("margin-bottom: 15px")
        # FIXME: copied code from above
        button.add_behavior( {
        'type': 'click_up',
        'cbjs_action': '''
        spt.tab.set_main_body_tab();
        var class_name = 'tactic.ui.app.HelpEditWdg';

        var element_name = spt.help.get_view();
        if (!element_name) {
          element_name = "default";
        }
        var kwargs = {
          view: element_name
        }

        spt.tab.add_new("help_edit", "Help Edit", class_name, kwargs);

        '''
        } )
        return div

__all__.append("HelpContentWideWdg")
class HelpContentWideWdg(BaseRefreshWdg):

    def get_display(self):
        top = self.top
        top.add_color("background", "background", -5)

        help = HelpContentWdg(**self.kwargs)
        top.add(help)

        help_top = help.top
        help_top.add_style("margin: -1 auto 10 auto")
        help_top.add_border()

        return top

class HelpContentWdg(BaseRefreshWdg):

    def get_display(self):
        top = self.top
        top.add_style("height: 100%")
        top.add_style("overflow-x: hidden")
        top.set_unique_id()

        width = self.kwargs.get("width")
        if width:
            top.add_style("width: %s" % width)

        from tactic.ui.panel import CustomLayoutWdg
        html = self.kwargs.get("html")
        view = self.kwargs.get("view")

        alias = self.kwargs.get("alias")
        if alias:
            aliases = alias.split("|")
            alias = aliases[0]
            aliases = aliases[1:]
        else:
            aliases = []

        top.add_relay_behavior( {
            'type': 'mouseover',
            'bvr_match_class': 'spt_link',
            'cbjs_action': '''
            spt.mouse.table_layout_hover_over({}, {src_el: bvr.src_el, add_color_modifier: -5});
            '''
        } )

        top.add_relay_behavior( {
            'type': 'mouseout',
            'bvr_match_class': 'spt_link',
            'cbjs_action': '''
            spt.mouse.table_layout_hover_out({}, {src_el: bvr.src_el})
            '''
        } )

        top.add_smart_style("spt_link", "margin-left", "5px")
        if alias == 'main':
            top.add_smart_style("spt_link", "text-decoration", "none")
        else:
            top.add_smart_style("spt_link", "text-decoration", "underline")
        top.add_smart_style("spt_link", "padding", "1px")

        if aliases:
            related_wdg = self.get_related_wdg(aliases)
            top.add( related_wdg )

        rel_path = self.kwargs.get("rel_path")

        # attempt to get if from the widget config
        search = Search("config/widget_config")
        search.add_filter("category", "HelpWdg")
        search.add_filter("view", alias)
        config = search.get_sobject()

        if html:
            layout = CustomLayoutWdg(html=html, view=view)
            top.add(layout)

        # config can override alias
        elif config:
            layout = CustomLayoutWdg(config=config, view=alias)
            author = config.get_value("login")
            timestamp = config.get_value("timestamp")
            top.add(layout)

        elif alias:
            widget = HelpDocFilterWdg(alias=alias)
            top.add(widget)

        elif rel_path:
            widget = HelpDocFilterWdg(rel_path=rel_path)
            top.add(widget)

        elif not view:
            layout = DivWdg()
            top.add(layout)
            allow_create = self.kwargs.get("allow_create")
            if allow_create not in ['false', False]:
                layout.add(HelpCreateWdg())
            else:
                layout.add("No documentation found")
                layout.add_style("padding: 30px 20px")
                layout.add_style("margin-left: auto")
                layout.add_style("margin-right: auto")
                layout.add_style("margin-top: 50px")
                layout.add_style("text-align: center")
                layout.add_style("width: 250px;")
                layout.add_color("background", "background3")
                layout.add_color("color", "color3")
                layout.add_border()

        elif view == 'default':
            top.add(self.get_default_wdg())

        else:
            author = "TACTIC"
            timestamp = None

            search = Search("config/widget_config")
            search.add_filter("category", "HelpWdg")
            search.add_filter("view", view)
            config = search.get_sobject()
            if config:
                layout = CustomLayoutWdg(config=config, view=view)
                author = config.get_value("login")
                timestamp = config.get_value("timestamp")

            else:
                # get it from the file system
                layout = DivWdg()
                install_dir = Environment.get_install_dir()
                path = "%s/src/context/help/%s.html" % (install_dir,view)
                if os.path.exists(path):
                    f = open(path)
                    html = f.read()
                    f.close()
                    layout.add(html)

                else:
                    div = DivWdg()
                    layout.add(div)
                    div.add_style("padding: 15px")
                    div.add_style("margin: 10px")
                    div.add_border()
                    div.add_color("background", "background", -5)
                    div.add_style("text-align: center")
                    div.add_style("font-weight: bold")

                    icon = IconWdg("WARNING", IconWdg.WARNING)
                    div.add(icon)
                    div.add("There are no help pages available for this key [%s]

" % view)
                    div.add("
")

                    div.add("Click to create a new custom doc:")
                    from tactic.ui.widget import ActionButtonWdg
                    button = ActionButtonWdg(title="Create", tip="Create docs for this view")
                    div.add(button)
                    button.add_style("margin-right: auto")
                    button.add_style("margin-left: auto")
                    button.add_style("margin-top: 15px")
                    button.add_style("margin-bottom: 15px")
                    # FIXME: copied code from above
                    button.add_behavior( {
                    'type': 'click_up',
                    'cbjs_action': '''
                    spt.tab.set_main_body_tab();
                    var class_name = 'tactic.ui.app.HelpEditWdg';

                    var element_name = spt.help.get_view();
                    if (!element_name) {
                      element_name = "default";
                    }
                    var kwargs = {
                      view: element_name
                    }

                    spt.tab.add_new("help_edit", "Help Edit", class_name, kwargs);

                    '''
                    } )

                layout.add_style("margin-top: 10px")

            info_div = DivWdg()
            info_div.add("Author: %s" % author)
            info_div.add_style("opacity: 0.5")
            info_div.add_style("font-size: 10px")
            info_div.add_style("position: absolute")
            info_div.add_style("bottom: 20px")

            content_div = DivWdg()
            top.add(content_div)
            content_div.add_style("padding: 5px")
            content_div.add(layout)

            top.add(info_div)

        #top.add(HelpContentWdg.get_default_wdg(aliases))

        return top

    def get_related_wdg(self, aliases):
        div = DivWdg()
        div.add("Related links:  &nbsp")
        div.add_style("margin-top: 5px")
        div.add_style("margin-bottom: 5px")
        div.add_style("margin-left: 10px")

        titles = [Common.get_display_title(x.replace("-"," ")) for x in aliases]
        for alias, title in zip(aliases, titles):

            link_div = SpanWdg()
            div.add(link_div)
            link_div.add_color("background", "background")
            link_div.add(title)
            link_div.add_behavior( {
                'type': 'click_up',
                'cbjs_action': '''
                spt.help.set_top();
                spt.help.load_alias("%s");
                ''' % alias
            } )
            link_div.add_class("spt_link")
            link_div.add_class("hand")

        return div

    def get_default_wdg(cls, aliases=[]):
        div = DivWdg()
        div.set_unique_id()
        div.add_style("padding: 5px")
        if aliases:
            div.add("Related links:

")

            titles = [Common.get_display_title(x.replace("-"," ")) for x in aliases]
            for alias, title in zip(aliases, titles):

                link_div = DivWdg()
                div.add(link_div)
                link_div.add_color("background", "background")
                link_div.add(title)
                link_div.add_behavior( {
                    'type': 'click_up',
                    'cbjs_action': '''
                    spt.help.set_top();
                    spt.help.load_alias("%s");
                    ''' % alias
                } )
                link_div.add_class("spt_link")
                link_div.add_class("hand")

            div.add("

")

        div.add("Additional useful links:

")
        aliases = ['setup', 'end_user', 'developer', 'sys_admin']
        titles = ['Project Setup Documentation', 'End User Documentation', 'Developer Documentation', 'System Administrator Documentation']

        for alias, title in zip(aliases, titles):

            link_div = DivWdg()
            div.add(link_div)
            link_div.add_color("background", "background")
            link_div.add(title)
            link_div.add_behavior( {
                'type': 'click_up',
                'cbjs_action': '''
                spt.help.set_top();
                spt.help.load_alias("%s");
                ''' % alias
            } )
            link_div.add_class("spt_link")
            link_div.add_class("hand")

        div.add("
")

        link_div = DivWdg()
        div.add(link_div)
        link_div.add("TACTIC Documentation (PDF)")
        link_div.add_color("background", "background")
        link_div.add_behavior( {
            'type': 'click_up',
            'cbjs_action': '''
            window.open("/doc/", "TACTIC Docs");
            '''
        } )
        link_div.add_class("spt_link")
        link_div.add_class("hand")

        link_div = DivWdg()
        div.add(link_div)
        link_div.add_color("background", "background")
        link_div.add("TACTIC Community Site")
        link_div.add_behavior( {
            'type': 'click_up',
            'cbjs_action': '''
            window.open("http://community.southpawtech.com", "TACTIC Community Site");
            '''
        } )
        link_div.add_class("spt_link")
        link_div.add_class("hand")

        return div

    get_default_wdg = classmethod(get_default_wdg)

class HelpEditWdg(BaseRefreshWdg):

    def get_display(self):

        top = self.top
        top.add_class("spt_help_edit_top")
        top.add_color("background", "background")

        view = self.kwargs.get("view")

        from tactic.ui.container import ResizableTableWdg
        table = ResizableTableWdg()
        top.add(table)
        table.add_color("color", "color")
        table.add_style("width: 100%")
        table.add_style("height: 500px")

        table.add_row()
        left = table.add_cell()
        left.add_color("background", "background3")

        title_wdg = Table()

        title_wdg.add_row()
        left.add(title_wdg)
        title_wdg.add_gradient("background", "background", 0, -10)
        title_wdg.add_style("padding: 5px")
        title_wdg.add_style("margin-bottom: 5px")
        title_wdg.add_style("width: 100%")

        title_div = DivWdg("Help Pages")
        title_cell = title_wdg.add_cell(title_div)
        title_cell.add_style("width: 100%")

        from tactic.ui.widget import ActionButtonWdg
        insert_button = ActionButtonWdg(title="+", size="small")
        insert_button.add_style("margin-top: -3px")
        insert_button.add_behavior( {
        'type': 'click_up',
        'cbjs_action': '''

        var class_name = "tactic.ui.panel.EditWdg"
        var view = "edit"
        var title = "Add new help doc"
        var cbjs_insert = "spt.tab.reload_selected();"
        var kwargs = {
          'view': view,
          'search_type': 'config/widget_config',
          'default': '{"category":"HelpWdg"}',
          'ignore': 'search_type|login|config',
          'mode': 'insert',
          //'cbjs_insert': cbjs_insert
        }

        spt.panel.load_popup(title, class_name, kwargs);

        '''
        })

        title_wdg.add_cell(insert_button)

        docs_wdg = self.get_doc_wdg()
        left.add(docs_wdg)
        left.add_style("width: 150px")
        left.add_style("min-width: 150px")
        left.add_style("min-height: 500px")
        left.add_style("vertical-align: top")
        left.add_border()

        right = table.add_cell()
        right.add_style("vertical-align: top")
        right.add_border()

        content = HelpEditContentWdg(view=view)
        right.add(content)

        return top

    def get_doc_wdg(self):
        div = DivWdg()

        search = Search("config/widget_config")
        search.add_filter("category", "HelpWdg")
        sobjects = search.get_sobjects()

        hover = div.get_color("background", -10)

        for sobject in sobjects:
            help_div = DivWdg()
            div.add(help_div)
            help_div.add_style("padding: 3px")

            view = sobject.get_value("view")
            help_div.add(view)

            help_div.add_class("hand")
            help_div.add_behavior( {
            'type': 'hover',
            'hover': hover,
            'cbjs_action_over': '''
            bvr.src_el.setStyle("background", bvr.hover);
            ''',
            'cbjs_action_out': '''
            bvr.src_el.setStyle("background", "");
            '''
            } )

            help_div.add_behavior( {
            'type': 'click_up',
            'view': view,
            'cbjs_action': '''
            var top = bvr.src_el.getParent(".spt_help_edit_top");
            var content = top.getElement(".spt_help_edit_content");

            var class_name = 'tactic.ui.app.HelpEditContentWdg';
            var kwargs = {
                view: bvr.view
            };

            spt.panel.load(content, class_name, kwargs);

            '''
            } )

        return div

class HelpEditContentWdg(BaseRefreshWdg):

    def get_display(self):
        top = self.top

        view = self.kwargs.get("view")
        top.add_class("spt_help_edit_content")

        search = Search("config/widget_config")
        search.add_filter("category", "HelpWdg")
        search.add_filter("view", view)
        sobject = search.get_sobject()

        if not sobject:
            value = ""
            search_key = ""

        else:
            xml_value = sobject.get_xml_value("config")
            value = xml_value.get_value("config/%s/html/div" % (view) )
            search_key = sobject.get_search_key()

        title_wdg = DivWdg()
        top.add(title_wdg)
        title_wdg.add("View: %s" % view)
        title_wdg.add_style("font-style: bold")
        title_wdg.add_style("padding: 5px")
        title_wdg.add_gradient("background", "background", 0, -10)

        hidden = HiddenWdg("view")
        top.add(hidden)
        hidden.set_value(view)

        text = TextAreaWdg("content")
        text_id = text.set_unique_id()
        text.set_value(value)

        from tactic.ui.widget import ActionButtonWdg
        if sobject:
            delete_button = ActionButtonWdg(title="Delete")
            top.add(delete_button)
            delete_button.add_style("float: right")
            delete_button.add_style("margin-top: -3px")
            delete_button.add_behavior( {
            'type': 'click_up',
            'search_key': search_key,
            'cbjs_action': '''
            if (!confirm("Are you sure you wish to delete this help page?")) {
                return;
            }
            var server = TacticServerStub.get();
            server.delete_sobject(bvr.search_key);
            var top = bvr.src_el.getParent(".spt_help_edit_top");
            spt.panel.refresh(top);
            '''
            })

        test_button = ActionButtonWdg(title="Preview")
        top.add(test_button)
        test_button.add_style("float: right")
        test_button.add_style("margin-top: -3px")
        test_button.add_behavior( {
        'type': 'click_up',
        'text_id': text_id,
        'cbjs_action': '''

        var js_file = "ckeditor/ckeditor.js";

        var url = "/context/spt_js/" + js_file;
        var js_el = document.createElement("script");
        js_el.setAttribute("type", "text/javascript");
        js_el.setAttribute("src", url);

        var head = document.getElementsByTagName("head")[0];
        head.appendChild(js_el);

        var cmd = "CKEDITOR.instances." + bvr.text_id + ".getData()";
        var text_value = eval( cmd );

        bvr.options = {};
        bvr.options.html = text_value;
        spt.named_events.fire_event("show_help", bvr)
        '''
        })

        save_button = ActionButtonWdg(title="Save")
        top.add(save_button)
        save_button.add_style("float: right")
        save_button.add_style("margin-top: -3px")

        top.add("
")

        save_button.add_behavior( {
        'type': 'click_up',
        'text_id': text_id,
        'cbjs_action': '''

        spt.app_busy.show("Saving Help", " ")

        var top = bvr.src_el.getParent(".spt_help_edit_content");
        var values = spt.api.Utility.get_input_values(top, null, false);

        var cmd = "CKEDITOR.instances." + bvr.text_id + ".getData()";
        var text_value = eval( cmd );
        values.content = text_value;

        var command = "tactic.ui.app.HelpEditCbk";
        var kwargs = values;
        var server = TacticServerStub.get();
        server.execute_cmd(command, kwargs);

        setTimeout("spt.app_busy.hide()", 200)
        '''
        } )

        #top.add("Style: ")
        #select = SelectWdg("style")
        #top.add(select)
        #select.set_option("values", "text|html")

        top.add("
")

        top.add(text)
        text.set_value(value)
        text.add_style("width: 100%")
        text.add_style("height: 100%")
        text.add_style("min-height: 500px")
        text.add_style("display: none")
        text.add_behavior( {
        'type': 'load',
        'color': text.get_color("background", -10),
        'text_id': text_id,
        'cbjs_action': '''

        var js_file = "ckeditor/ckeditor.js";
        var url = "/context/spt_js/" + js_file;
        var js_el = document.createElement("script");
        js_el.setAttribute("type", "text/javascript");
        js_el.setAttribute("src", url);
        var head = document.getElementsByTagName("head")[0];
        head.appendChild(js_el);

        setTimeout( function() {

        CKEDITOR.on( 'instanceReady', function( ev )
        {
            ev.editor.dataProcessor.writer.indentationChars = ' ';
        });

        var config = {
          toolbar: 'Full',
          uiColor: bvr.color,
          height: '500px'
        };
config.toolbar_Full =
[
    ['Source'],
    ['Cut','Copy','Paste'],
    ['Undo','Redo','-','Find','Replace'],
    ['Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],
    ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
    '/',
    ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
    ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
    ['HorizontalRule','SpecialChar'],
    ['Styles','Format','Font','FontSize'],
    ['TextColor','BGColor'],
    ['Maximize', 'ShowBlocks']
];

        CKEDITOR.replace(bvr.text_id, config );
        bvr.src_el.setStyle("display", "");

        }, 500);
        '''
        } )

        return top

class HelpEditCbk(Command):
    def execute(self):

        view = self.kwargs.get("view")
        content = self.kwargs.get("content")

        search = Search("config/widget_config")
        search.add_filter("category", "HelpWdg")
        search.add_filter("view", view)
        config = search.get_sobject()
        if not config:
            config = SearchType.create("config/widget_config")
            config.set_value("category", "HelpWdg")
            config.set_value("view", view)

        config_xml = '''
<config>
  <%s>

<![CDATA[
%s
]]>

  </%s>
</config>
''' % (view, content, view)

        config.set_value("config", config_xml)

        config.commit()

{'TacticServerStub': 'tactic_client_lib.TacticServerStub', 'CustomLayoutWdg': 'tactic.ui.panel.CustomLayoutWdg', 're': 're', 'Image': 'PIL.Image'}


from __future__ import print_function
from collections import defaultdict
import os, time, sys
import xml.etree.ElementTree as ET
import mbcat.utils
import mbcat
import logging
_log = logging.getLogger("mbcat")
try:
    from StringIO import StringIO
except ImportError as e:
    from io import StringIO

class PurchaseEvent:

    def __init__(self, date, price, vendor):
        # Do these calls use the implicit property calls?
        self.date = date
        self.price = price
        self.vendor = vendor

    def getDate(self):
        try:
            return time.strftime(mbcat.dateFmtStr, time.localtime(self._date))
        except TypeError:
            return ''
        except AttributeError:
            return ''

    def setDate(self, date):
        try:
            self._date = time.strptime(date, mbcat.dateFmtStr)
        except ValueError as e:
            _log.warning(e)

    date = property(getDate, setDate, doc='purchase date')

    def getPrice(self):
        try:
            return "%.2f" % (self._price / 100)
        except AttributeError:
            return ''

    def setPrice(self, price):
        try:
            self._price = int(float(price) * 100)
        except ValueError as e:
            _log.warning(e)

    price = property(getPrice, setPrice, doc='purchase price')

    def __str__(self):
        return "Purchased on "+self.date+" from "+self.vendor+" for "+self.price

class CheckInEvent:
    def __init__(self, date):
        self._date = date

    def getDate(self):
        return time.strftime(mbcat.dateFmtStr, time.localtime(self._date))

    def setDate(self, date):
        self._date = time.strptime(date, mbcat.dateFmtStr)

    date = property(getDate, setDate, doc='purchase date')

    def __str__(self):
        return "Returned on: " + self.date

class CheckOutEvent(CheckInEvent):
    """Same as CheckInEvent, but adds a borrower field"""
    def __init__(self, borrower, date):
        self._date = date
        self.borrower = borrower

    def __str__(self):
        return "Lent on: " + self.date + " to: " + self.borrower

class DigitalPath:
    def __init__(self, path, digiFormat):
        self.path=path
        self.digiFormat=digiFormat

# TODO add list of listening events
# TODO add path to audio files on system
class ExtraData:
    def __init__(self, releaseId, path='release-id'):
        if releaseId.startswith('http'):
            releaseId = utils.extractUuid(releaseId, 'release')
        self.path = os.path.join(path, releaseId, 'extra.xml')
        self.purchases = []
        self.addDates = []
        self.lendEvents = []
        self.listenEvents = []
        self.digitalPaths = []
        self.comment = ""
        self.rating = 0

    def load(self):
        tree = ET.parse(self.path).getroot()
        return self.parseTree(tree)

    def loads(self, string):
        tree = ET.fromstring(string)
        return self.parseTree(tree)

    def parseTree(self, root):
        for purchase in root.findall('./purchase'):
            self.purchases.append(PurchaseEvent( \
                    purchase.attrib['date'], \
                    purchase.attrib['price'], \
                    purchase.attrib['vendor'] ) )
        for added in root.findall('./added'):
            self.addDates.append(float(added.attrib['date']))
        for comment in root.findall('./comment'):
            self.comment = comment.text
        for rating in root.findall('./rating'):
            self.rating = int(rating.text)
        for lendList in root.findall('./lendlist'):
            for lend in lendList:
                if lend.tag != 'lent':
                    continue
                self.lendEvents.append(CheckOutEvent(lend.attrib['who'], \
                    int(lend.attrib['date'])))
        for pathList in root.findall('./digital'):
            for path in pathList:
                if path.tag != 'path':
                    continue
                if path.text:
                    self.addPath(path.text)

        return root

    def toElement(self):
        root = ET.Element('extra')
        root.text="\n"
        for purchase in self.purchases:
            pe = ET.SubElement(root, 'purchase', attrib={ \
                    'date':purchase.date, \
                    'price':purchase.price, \
                    'vendor':purchase.vendor})
            pe.tail="\n"
        for addDate in self.addDates:
            pe = ET.SubElement(root, 'added', attrib={ \
                    'date':"%d" % addDate})
            pe.tail="\n"
        c = ET.SubElement(root, 'comment')
        c.text=self.comment
        c.tail="\n"
        r = ET.SubElement(root, 'rating')
        r.text=str(self.rating)
        r.tail="\n"
        ll = ET.SubElement(root, 'lendlist')
        ll.tail="\n"
        for lendEvent in self.lendEvents:
            le = ET.SubElement(ll, 'lent', \
                    attrib={
                        'date':'%d' % lendEvent._date,
                        'who':lendEvent.borrower})
            le.tail="\n"
        dl = ET.SubElement(root, 'digital')
        dl.tail="\n"
        for path in self.digitalPaths:
            de = ET.SubElement(dl, 'path') # TODO could add format as attrib
            de.text=path
            de.tail="\n"
        return root

    def save(self):
        et = ET.ElementTree(self.toElement())
        et.write(self.path)

    def toString(self):
        memF = StringIO()
        et = ET.ElementTree(self.toElement())
        et.write(memF)
        memF.seek(0)
        return memF.read()

    def __str__(self):
        return "Extra Data:\n" + \
                "\n".join([str(purchase) for purchase in self.purchases]) + \
                ("\nComment: " + self.comment if self.comment else "") + \
                ("\nRating: %d / 5" % self.rating) + \
                (("\n".join([str(lend) for lend in self.lendEvents])) if self.lendEvents else "") + \
                "\n"

    def addDate(self, date=time.time()):
        self.addDates.append(date)

    def addLend(self, borrower, date):
        if not date:
            #date = time.strftime(dateFmtStr)
            date = time.time()
        self.lendEvents.append(CheckOutEvent(borrower, date))

    def setRating(self, rating=0):
        self.rating = int(rating)

    def addPath(self, path):
        if path not in self.digitalPaths:
            self.digitalPaths.append(path)

    def addPurchase(self, purch):
        self.purchases.append(purch)


from __future__ import absolute_import, division, print_function
#!/usr/bin/env python

from scitbx import matrix
from rstbx.bpcx import sensor
from six.moves import range

class detector:
    '''An abstract class definition for X-ray detectors which are assumed to
    be composed of one or more flat rectangular sensor areas. Will initially
    assume that sensor areas to not shadow one another.'''

    def __init__(self, sensors):
        self._sensors = sensors

        return

    def sensors(self):
        return self._sensors

class reflection_predictor:
    '''A class to convert supplied diffraction vectors and detector surfaces
    to impact positions as sensor number and mm in the coordinate frame
    attached to that sensor. Need to return number of sensor and coordinate.
    The units of mm are not enforced - it is whatever the detector matrix d
    is set up with'''

    def __init__(self, rays, sensors):

        self._rays = rays
        self._sensors = sensors
        return

    def intersections(self):
        '''Calculate intersections for each diffracted ray in the list'''

        intersections = []
        for ray in self._rays:
            x = self.intersect_all_sensors(ray)
            if x:
                intersections.append(x)

        return intersections

    def intersect_all_sensors(self, ray):
        # basic way - we have to check the vector against each sensor in turn.
        # there may be more efficient short cuts

        hit = None
        for j, s in enumerate(self._sensors):
            x = self.intersect(ray, s)
            if x:
                if hit is None:
                    dist = (matrix.col(s.origin) + \
                            x[0] * matrix.col(s.dir1) + \
                            x[1] * matrix.col(s.dir2)).length()
                    hit = (j, x[0], x[1], dist)
                else:
                    dist = (matrix.col(s.origin) + \
                            x[0] * matrix.col(s.dir1) + \
                            x[1] * matrix.col(s.dir2)).length()
                    if dist < hit[3]:
                        hit = (j, x[0], x[1], dist)
        return hit

    def intersect(self, ray, sensor):
        '''Compute intersection of sensor with ray from frame origin, returning
        none if intersection not within limits.'''
        raise RuntimeError('overload me')

class reflection_predictor_thomas(reflection_predictor):
    '''Implementation of reflection_predictor using David Thomas' matrix
    formalism'''

    def intersect(self, ray, sensor):
        v = matrix.sqr(sensor.D) * ray
        x1 = v[0] / v[2]
        x2 = v[1] / v[2]

        if x1 < sensor.lim1[0] or x1 > sensor.lim1[1]:
            return None
        if x2 < sensor.lim2[0] or x2 > sensor.lim2[1]:
            return None

        return (x1, x2)

class reflection_predictor_trivial(reflection_predictor):
    '''Implementation of reflection_predictor using the vectors directly'''

    def intersect(self, ray, sensor):
        scale = ray.dot(matrix.col(sensor.normal))
        r = (ray * sensor.distance / scale) - matrix.col(sensor.origin)
        x1 = r.dot(matrix.col(sensor.dir1))
        x2 = r.dot(matrix.col(sensor.dir2))
        if x1 < sensor.lim1[0] or x1 > sensor.lim1[1]:
            return None
        if x2 < sensor.lim2[0] or x2 > sensor.lim2[1]:
            return None

        return (x1, x2)

def predictor_factory(selection):
    '''Factory function to choose a suitable implementation of the
    reflection_predictor class. This is a basic version to flesh out the API.
    A more realistic version might use e.g. PHIL parameters to make the choice
    and would not hard code the alternatives'''

    class_choice = {
        'matrix': reflection_predictor_thomas,
        'vector': reflection_predictor_trivial
    }.get(selection)

    return class_choice

def test_all():
    '''Test all features of the module using a detector composed of four
    overlapping square sensors.'''

    d1 = matrix.col((1, 0, 0))
    d2 = matrix.col((0, 1, 0))
    lim = (0,50)
    panel0 = sensor(matrix.col((-45, -45, 100)), d1, d2, lim, lim)
    panel1 = sensor(matrix.col((-5, -45, 99)), d1, d2, lim, lim)
    panel2 = sensor(matrix.col((-45, -5, 98)), d1, d2, lim, lim)
    panel3 = sensor(matrix.col((-5, -5, 97)), d1, d2, lim, lim)

    d = detector([panel0, panel1, panel2, panel3])
    rays = [matrix.col((0, 0, 1))]

    for ver in ('matrix', 'vector'):
        rp = predictor_factory(ver)
        rp = rp(rays, d.sensors())

        # only one ray to consider
        rpi = rp.intersections()

        # the closest intersection should be on panel3
        assert rpi[0][0] == 3

    print('OK')

def test_work():
    '''Test all features of the module using a detector composed of four
    overlapping square sensors, with lots of rays.'''

    import random, time

    nrays = 10000

    d1 = matrix.col((1, 0, 0))
    d2 = matrix.col((0, 1, 0))
    lim = (0,50)
    panel0 = sensor(matrix.col((-45, -45, 100)), d1, d2, lim, lim)
    panel1 = sensor(matrix.col((-5, -45, 99)), d1, d2, lim, lim)
    panel2 = sensor(matrix.col((-45, -5, 98)), d1, d2, lim, lim)
    panel3 = sensor(matrix.col((-5, -5, 97)), d1, d2, lim, lim)

    d = detector([panel0, panel1, panel2, panel3])

    rays = [matrix.col((random.random() - 0.5,
                        random.random() - 0.5,
                        random.random() - 0.5)) for j in range(nrays)]

    rpi = { }

    for ver in ('matrix', 'vector'):
        t0 = time.time()
        rp = predictor_factory(ver)(rays, d.sensors())

        rpi[ver] = rp.intersections()

    for j, intersection_matrix in enumerate(rpi['matrix']):
        intersection_vector = rpi['vector'][j]
        assert(intersection_matrix[0] == intersection_vector[0])

    print('OK')

if __name__ == '__main__':
    test_work()


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('main', '0002_topics'),
    ]

    operations = [
        migrations.CreateModel(
            name='Pages',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('menu', models.CharField(max_length=50)),
                ('subject', models.CharField(max_length=100)),
                ('intro', models.TextField(max_length=255)),
            ],
            options={
            },
            bases=(models.Model,),
        ),
        migrations.AlterField(
            model_name='topics',
            name='cata_icon',
            field=models.CharField(default=b'education', max_length=32, choices=[(b'education', b'IntroIR'), (b'discovery', b'Opendata'), (b'culture', b'IssueAnaly'), (b'people', b'IRdb')]),
            preserve_default=True,
        ),
    ]


import numpy as np
from ui_qt import UI
from setup import PhysicalSetup, RNGBasedSetup, FileBasedSetup, SineWaveBasedSetup, ZeroSetup
import argparse
from algorithms import algorithms

def main():

    setup_map = {
        'phy' : PhysicalSetup,
        'rng' : RNGBasedSetup,
        'file' : FileBasedSetup,
        'sin' : SineWaveBasedSetup,
        'zero' : ZeroSetup
    }

    parser = argparse.ArgumentParser(
        prog='Surgial Robots Project',
        description='Recieves data from setup plots the results and saves them',
        epilog='For more info contact Ajinkya Kamat (ajinkyak@andrew.cmu.edu)'
    )

    parser.add_argument('-s', '--setup', choices=setup_map.keys(), default='phy')
    parser.add_argument('-a', '--azimuth', required=True, type=float)
    parser.add_argument('-e', '--elevation', required=True, type=float)
    args = parser.parse_args()

    setup = setup_map[args.setup]()
    force_orientation = (np.deg2rad(args.azimuth), np.deg2rad(args.elevation))

    timestamps = np.ndarray((1, 0))
    raw_readings = np.ndarray((3, 0))
    measured_forces = np.ndarray((3, 0))

    ui = UI(setup.set_force)

    while True:

        timestamp, raw_reading, measured_force_reading = setup.get_readings()

        measured_force = np.array([
            [measured_force_reading * np.cos(force_orientation[0]) * np.cos(force_orientation[1])],
            [measured_force_reading * np.sin(force_orientation[0]) * np.cos(force_orientation[1])],
            [measured_force_reading * np.sin(force_orientation[1])]
        ])

        timestamps = np.append(timestamps, timestamp)
        raw_readings = np.hstack([raw_readings, raw_reading])
        measured_forces = np.hstack([measured_forces, measured_force])

        infered_forces = {name : algorithm(timestamps, raw_readings) for (name, algorithm) in algorithms.items()}
        ui.update(timestamps, raw_readings, infered_forces, measured_forces, force_orientation)

if __name__ == '__main__':
    main()


import asyncio
import pandas as pd
import re

from bs4 import BeautifulSoup
import aiohttp
from urllib.parse import urljoin
from typing import List, Tuple
from util import print_progress_bar
from lekopttorg.config import ADDRESS

class ParserLekopttorg:
    URL = 'https://lekopttorg.ru/'
    PAGE = '?PAGEN_3={num}'
    PHARMACY = 'ЛекОптТорг'
    URL_ADDRESS = 'https://lekopttorg.ru/bitrix/services/main/ajax.php?mode=class&c=webit.custom%3Astores.list&action=getStores'

    def __init__(self, max_request: int = 10):
        self.data = {'name': [], 'producer': [], 'cost': [], 'url': [], 'address': [], 'id': []}
        self.max_request = max_request
        self.all_address = set()

    async def run_parser(self):
        """Запуск парсера"""
        async with aiohttp.ClientSession() as session:
            catalogs_urls = await self._get_category_urls(session)
            for name, url in catalogs_urls.items():
                await self._pars_product(url, session)
            await self._get_address(session)
        await self._create_df()

    async def _create_df(self) -> None:
        """Формирование структыры таблицы"""
        self.data.update({i: 0 for i in self.all_address})
        df = pd.DataFrame(self.data)
        if not ADDRESS:
            all_address = list(self.all_address)
        else:
            all_address = list(ADDRESS)
        all_address.sort()
        for i in all_address:
            df[i] = df.apply(lambda row: row['cost'] if i in row['address'] else 0, axis=1)
        df['min'] = df['cost'].copy()
        df['max'] = df['cost'].copy()
        result = df[['name', 'producer', 'min', 'max'] + all_address]
        result.to_excel(f'result/{self.PHARMACY}.xlsx')

    async def _get_address_data(self, data: Tuple[str, int], session: aiohttp.ClientSession) -> None:
        """Получение данных адресов"""
        csrf = re.search(r"'bitrix_sessid':'(.+)'", data[0])[1]
        body = {
            'id': self.data['id'][data[1]],
            'filter': {'hours24': False, 'optika': False, 'search': '', 'view': 'map'}
        }
        headers = {
            "Referer": self.data['url'][data[1]],
            "X-Bitrix-Csrf-Token": csrf
        }
        all_address = []
        async with session.post(self.URL_ADDRESS, headers=headers, json=body) as result:
            address = await result.json()
            for i in address['data']['STORES']:
                all_address.append(i['NAME'])
        self.all_address.update(all_address)
        self.data['address'][data[1]] = all_address

    async def _get_address(self, session: aiohttp.ClientSession):
        """Получение адресов"""
        pending = [self._fetch_address(session, i, ind) for ind, i in enumerate(self.data['url'])]
        self.data['address'] = [[] for _ in range(len(self.data['url']))]

        print('Получение данных о наличии в аптеках')
        progress = 0
        max_progress = len(pending)
        print_progress_bar(progress, max_progress, prefix='Progress:', suffix='Complete', length=50)

        while pending:
            sub_pending = [asyncio.create_task(i) for i in pending[:self.max_request]]
            del pending[:self.max_request]
            while sub_pending:
                done, sub_pending = await asyncio.wait(
                    sub_pending, return_when=asyncio.FIRST_COMPLETED
                )

                for done_task in done:
                    get_data = await done_task
                    await self._get_address_data(get_data, session)
                progress += len(done)
                print_progress_bar(progress, max_progress, prefix='Progress:', suffix='Complete', length=50)

    async def _get_category_urls(self, session: aiohttp.ClientSession) -> dict:
        """Получение данных категорий"""
        async with session.get(self.URL) as result:
            result = await result.text()
        soup = BeautifulSoup(result, 'lxml')
        data = soup.find('nav', class_='header__nav invis-scroll')
        links = data.find_all('a', class_='header__link')
        menu = {}
        for i in links:
            menu[i.text.strip()] = i.attrs['href']
        return menu

    async def _pars_product(self, url: str, session: aiohttp.ClientSession) -> None:
        """Получает данные о всех товарах по ссылке категории"""
        url_cat = urljoin(self.URL, url)
        result = await self._fetch(session, url_cat)
        pages = await self._get_all_pages(result)
        await self._get_product_data(data=result)
        pending = [self._fetch(session, f"{url_cat}{i}") for i in pages]

        progress = 0
        max_progress = len(pending)
        print_progress_bar(progress, max_progress, prefix='Progress:', suffix='Complete', length=50)
        while pending:
            sub_pending = [asyncio.create_task(i) for i in pending[:self.max_request]]
            del pending[:self.max_request]
            while sub_pending:
                done, sub_pending = await asyncio.wait(
                    sub_pending, return_when=asyncio.FIRST_COMPLETED
                )

                for done_task in done:
                    await self._get_product_data(await done_task)
                progress += len(done)
                print_progress_bar(progress, max_progress, prefix='Progress:', suffix='Complete', length=50)

    @staticmethod
    async def _fetch(session: aiohttp.ClientSession, url: str) -> str:
        """Запрос данных"""
        async with session.get(url) as result:
            return await result.text()

    @staticmethod
    async def _fetch_address(session: aiohttp.ClientSession, url: str, ind: int) -> Tuple[str, int]:
        """Запрос данных"""
        async with session.get(url) as result:
            data = await result.text()
            return data, ind

    async def _get_all_pages(self, data: str) -> List[str]:
        """Получение всех страниц в категории"""
        soup = BeautifulSoup(data, 'lxml')
        pages = soup.find('div', class_='pagintaion__number')
        last_page = int(pages.find_all('a')[-1].text.strip())
        return [self.PAGE.format(num=i+1) for i in range(last_page) if i]

    async def _get_product_data(self, data: str) -> None:
        """Получение данных продуктов со страницы"""
        soup = BeautifulSoup(data, 'lxml')
        all_products = soup.find('div', class_='catalog-line')
        for product in all_products.find_all('div', class_='product'):
            try:
                product_id = int(product.attrs['id'].split('-')[-1])
                content = product.find('div', class_='product__content')
                product_obj = content.find('a')
                product_name = product_obj.text.strip()
                product_url = urljoin(self.URL, product_obj.attrs['href'])
                producer_name = content.find('span', class_='val').text.strip()
                cost = product.find('span', class_='price__regular').text.strip()
                self.data['name'].append(product_name)
                self.data['producer'].append(producer_name)
                self.data['cost'].append(cost)
                self.data['url'].append(product_url)
                self.data['id'].append(product_id)
            except AttributeError:
                print(product)


from PIL import Image, ImageDraw
import csv

def draw(file,name):
    width = 28 # ширина изображения
    height = 28 # высота изображения
    image = Image.new("L", (width,height)) # режим - изображения в оттенках серого
    draw = ImageDraw.Draw(image)
    with open(file, encoding='utf-8') as r_file:
       # Создаем объект reader, указываем символ-разделитель ","
       file_reader = csv.reader(r_file, delimiter = ",")
       count = 0 # Счетчик для подсчета количества строк и вывода заголовков столбцов
       j = 0 #для названия файлов
       for line in file_reader:
           if count == 0:
               print(f'Файл содержит столбцы: {", ".join(line)}')
           else:
               pix = line
               i = 0
               label = pix[i] # нулевой символ в массиве - метка изображения
               i = 1
               for x in range(width):
                   for y in range(height):
                       pix[i] = int(pix[i])
                       pix[i] = 255 - pix[i] # 0 - background(white), 255 - foreground (black)
                       draw.point((y,x), (pix[i])) # рисуем по точкам
                       i = i + 1
               j = str(j)
               image.save(f"fashion_mnist\\{name}\\{label}\\img{j}.jpg", "JPEG")
               j = int(j)
               j = j + 1
           count += 1
    r_file.close()

file1 = "fashion-mnist_train.csv"
file2 = "fashion-mnist_test.csv"
draw(file1,"train")
draw(file2,"test")


'''

Plots the test execution times for the routing algorithms.

'''

import numpy as np
import matplotlib.pyplot as plt

save_figs = True # save figures or show figures

#
# Defintions
#

class Router:
    GREEDY_ROUTER = "GreedyRouter"
    DROPLET_SIZE_ROUTER = "DropletSizeAwareGreedyRouter"

class Attributes:
    SEED = 0
    COMPLETED = 1
    EXECUTION_TIME = 2
    COMPILE_TIME = 3

#
# Test reading
#

def get_file_names():
    import os
    return os.listdir()

def read_file(filename):
    import os
    import re

    f = open(filename, "r")
    content = f.read().rstrip() # remove trailing white spaces

    return content.replace(",", ".") # some systems use ',' for floating point in Java. However, Python expects '.', e.g. 3.1415

def get_full_test_name(router, test_name):
    return "{}_{}.txt".format(router, test_name)

def read_test_file(router, test):
    name = get_full_test_name(router, test)
    return read_file(name)

def get_test_files():
    files = get_file_names()
    extension = ".txt"
    return [file for file in files if file.endswith(extension)]

#
# Test processing
#

def extract_test(test_content):
    lines = test_content.split("\n")
    raw_content = [line.split(" ") for line in lines]
    return [(int(seed), bool(completed), int(execution_time), float(running_time)) for (seed, completed, execution_time, running_time) in raw_content]

def get_test(router, test):
    return extract_test(read_test_file(router, test))

def get_test_by_fullname(name):
    return extract_test(read_file(name))

def extract_attribute_from_test(attribute_index, test_content, skip_failed=True):
    return [test[attribute_index] for test in test_content if test[Attributes.COMPLETED]]

def get_average_execution_time(test_content, skip_failed=True):
    execution_times = extract_attribute_from_test(Attributes.EXECUTION_TIME, test_content, skip_failed)
    return np.mean(execution_times)

def get_all_average_execution_time(router, test_files):
    return [get_average_execution_time(get_test_by_fullname(file)) for file in test_files if file.startswith(router)]

def get_average_compile_time(test_content, skip_failed=True):
    execution_times = extract_attribute_from_test(Attributes.COMPILE_TIME, test_content, skip_failed)
    return np.mean(execution_times)

def get_all_average_compile_time(router, test_files):
    return [get_average_compile_time(get_test_by_fullname(file)) for file in test_files if file.startswith(router)]

#
# Plotting
#

def plot_combined_compile_time_tests():
    test_files = get_test_files()

    greedy_average_execution_times = get_all_average_compile_time(Router.GREEDY_ROUTER, test_files)
    droplet_average_execution_times = get_all_average_compile_time(Router.DROPLET_SIZE_ROUTER, test_files)

    fig, ax = plt.subplots()

    assert(len(greedy_average_execution_times) == len(droplet_average_execution_times))
    tests = np.arange(len(greedy_average_execution_times))

    colors = ['C0', 'C1']

    for x, ha, hb in zip(tests, greedy_average_execution_times, droplet_average_execution_times):
        for i, (h, c) in enumerate(sorted(zip([ha, hb], colors))):
            ax.bar(x, h, color=c, zorder=-i)

    #plt.legend(["Greedy Router", "Droplet Size-aware Greedy Router"], loc='lower right')
    ax.set_xlabel("Test (no.)")
    ax.set_xticks(tests)
    ax.set_ylabel("Compile-time (secs)")
    ax.set_title("Average Compile-times")

    if save_figs:
        filename = "compile_tile_combined_tests"
        plt.savefig(filename)
    else:
        fig.show()

    plt.close(fig)

def plot_combined_execution_time_tests():
    test_files = get_test_files()

    greedy_average_execution_times = get_all_average_execution_time(Router.GREEDY_ROUTER, test_files)
    droplet_average_execution_times = get_all_average_execution_time(Router.DROPLET_SIZE_ROUTER, test_files)

    fig, ax = plt.subplots()

    assert(len(greedy_average_execution_times) == len(droplet_average_execution_times))
    tests = np.arange(len(greedy_average_execution_times))

    colors = ['C0', 'C1']

    for x, ha, hb in zip(tests, greedy_average_execution_times, droplet_average_execution_times):
        for i, (h, c) in enumerate(sorted(zip([ha, hb], colors))):
            ax.bar(x, h, color=c, zorder=-i)

    #plt.legend(["Greedy Router", "Droplet Size-aware Greedy Router"], loc='lower right')
    ax.set_xlabel("Test (no.)")
    ax.set_xticks(tests)
    ax.set_ylabel("Execution-time (steps)")
    ax.set_title("Average Execution-times")

    if save_figs:
        filename = "execution_time_combined_tests"
        fig.savefig(filename)
    else:
        fig.show()

    plt.close(fig)

def plot_single_test_seeds(test_name):
    greedy_router_test = get_test(Router.GREEDY_ROUTER, test_name)
    droplet_size_router_test = get_test(Router.DROPLET_SIZE_ROUTER, test_name)

    fig, ax = plt.subplots(figsize=(15,5))

    greedy_seeds = extract_attribute_from_test(Attributes.SEED, greedy_router_test)
    droplet_size_seeds = extract_attribute_from_test(Attributes.SEED, droplet_size_router_test)
    assert(greedy_seeds == droplet_size_seeds)

    greedy_execution_times = extract_attribute_from_test(Attributes.EXECUTION_TIME, greedy_router_test)
    droplet_size_execution_times = extract_attribute_from_test(Attributes.EXECUTION_TIME, droplet_size_router_test)

    colors = ['C0', 'C1']

    for x, ha, hb in zip(greedy_seeds, greedy_execution_times, droplet_size_execution_times):
        for i, (h, c) in enumerate(sorted(zip([ha, hb], colors))):
            ax.bar(x, h, color=c, zorder=-i)

    #ax.legend(["Greedy Router", "Droplet Size-aware Greedy Router"], loc='lower right')
    ax.set_xlabel("Seed (no.)")
    ax.set_ylabel("Execution-time (steps)")
    ax.set_title("Execution-time of {} using {} seeds".format(test_name, len(greedy_seeds)))

    if save_figs:
        filename = "single_test_dist"
        fig.savefig(filename)
    else:
        fig.show()

    plt.close(fig)

#
# Summary
#
def print_summary():
    test_files = get_test_files()

    greedy_average_execution_times = get_all_average_execution_time(Router.GREEDY_ROUTER, test_files)
    droplet_average_execution_times = get_all_average_execution_time(Router.DROPLET_SIZE_ROUTER, test_files)

    greedy_total_average_execution_times = np.mean(greedy_average_execution_times);
    droplet_total_average_execution_times = np.mean(droplet_average_execution_times);

    print(greedy_total_average_execution_times, droplet_total_average_execution_times)

#
# function calls
#

plot_single_test_seeds("InVitro2")
plot_combined_execution_time_tests()
plot_combined_compile_time_tests()
print_summary()


from django.shortcuts import redirect, render
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_exempt
from .models import Book
from .forms import BookForm
# Create your views here.
def index(request):
    all_books = Book.objects.all()
    return render(request, 'book_store/book_list.html', context={"books": all_books})

def books_list(request):
    all_books = Book.objects.all()
    return render(request, 'book_store/books_list.html', context={"books": all_books})

def book_detail(request, pk):
    book = Book.objects.get(pk=pk)
    return render(request, 'book_store/book_details.html', context={"book": book})

def book_delete(request, pk):
    Book.objects.get(pk=pk).delete()
    return redirect('bookStore:books-list')

def book_update(request, pk):
    book = Book.objects.get(pk=pk)
    form = BookForm(instance=book)
    if request.method == "PUT":
        form = BookForm(data=request.POST, instance=book)
        if form.is_valid():
            form.save()
            return redirect("bookStore:book-update", pk=book.id)

    return render(request, 'book_store/book_update.html', context={
        'form': form,
        'book': book
    })

def create(request):
    form = BookForm()
    if request.method == "POST":
        form = BookForm(data=request.POST)
        if form.is_valid():
            form.save()
            return redirect("bookStore:books-list")
    return render(request, 'book_store/book_create.html', context={
        'form': form
    })


import table
import sqlite3 as sql
table.create_table()
connection = sql.connect("audio.sqlite", check_same_thread=False)

def store_audio(name, file):
    cursor = connection.cursor()
    cursor.execute("INSERT INTO playlist (name, song) VALUES (?, ?)", (name, file))
    cursor.connection.commit()
    cursor.close()
    connection.close()

if __name__ == "__main__":
    with open("bts.mp3", "rb") as read_song:
        data = read_song.read()
        print(type(data))
        # store_audio("bts", data)


# No puede ser un jupiter, tiene que ser archivo .py

from flask import Flask, flash, request, render_template, redirect, url_for
import pandas as pd
import os
import json

UPLOAD_FOLDER = os.sep + "static" + os.sep
# Flask es una clase cuyo primer atributo es un atributo obligatorio (name):
app = Flask(__name__)   # El atributo name es el nombre del archivo desde donde los estoy ejecutando
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.secret_key = 'hellohello'

# Estas dos funciones van a ser accesibles desde la API
@app.route("/") #esta función es la que se va a llamar por defecto
def home():
    return render_template("upload.html",
                           Genre_list = options["Genre_list"],
                           Platform_list= options["Platform_list"],
                           Publisher_list= options["Publisher_list"])

@app.route("/upload_form", methods = ['POST', 'GET'])
def upload_form():
    if request.method == 'POST':
        genre_res = request.form['Genre']
        platform_res= request.form['Platform']
        publisher_res = request.form['Publisher']
        all_returned = str(genre_res) + str(platform_res) + str(publisher_res)
        return json.dumps({"genre": genre_res,
                            "platform": platform_res,
                            "publisher": publisher_res,
                            "all_returned": all_returned})

if __name__ == '__main__':
    # host='127.0.0.1' --> No permite recibir llamadas desde el exterior
    # host='0.0.0.0' --> Permite recibir llamadas desde el exterior (primer paso pero no el ultimo, habria luego que \
    # cambiar el router)
    # si 0.0.0.0 no funciona externamente desde la IP privada de tu PC
    # es que tu ordenador o del dispositivo desde el que se accede
    # tiene bloqueada la conexión (antivirus / firewall)
    app.run(host='127.0.0.1',port=os.getenv("PORT", 1991), debug=True)
    #app es la clase de la instancia Class


import pickle
import string
import pandas as pd
import sklearn

news_df = pd.read_csv("input/uci-news-aggregator.csv", sep=",")
news_df['CATEGORY'] = news_df.CATEGORY.map({'b': 1, 't': 2, 'e': 3, 'm': 4})
news_df['TITLE'] = news_df.TITLE.map(
    lambda x: x.lower().translate(str.maketrans('', '', string.punctuation))
)
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    news_df['TITLE'],
    news_df['CATEGORY'],
    random_state=1
)
from sklearn.feature_extraction.text import CountVectorizer

count_vector = CountVectorizer(stop_words='english')
training_data = count_vector.fit_transform(X_train)
print(training_data)

from sklearn.naive_bayes import MultinomialNB
naive_bayes = MultinomialNB()
naive_bayes.fit(training_data, y_train)
filename = 'News_finalized_model.sav'
pickle.dump(naive_bayes, open(filename, 'wb'))


import os
import csv
import cv2
import numpy as np
import tensorflow as tf
from PIL import Image
from predicts_utils import multi_scale_predict
from deeplab_v3 import Deeplab_v3
from color_utils import color_predicts
from metric_utils import iou

ckpt_path = './ckpts/rgbt-72f-wloss-1130/rgbt-72f-wloss-1130-20000.ckpt'
model_name = 'rgbt-72f-wloss-1130-BGR'
dataset = 'rgbt_balance'
model_type = 'rgbt'
test_list_path = dataset + '/test_list.csv'
result_dir = './results/' + model_name
os.mkdir(result_dir)

def restore_model(saved_file):
    # Restore the model using parameters dict
    variables = tf.global_variables()
    param_dict = {}
    for var in variables:
        var_name = var.name[:-2]
        print('Loading {} from checkpoint. Name: {}'.format(var.name, var_name))
        param_dict[var_name] = var
    saver = tf.train.Saver()
    saver.restore(sess, saved_file)

# Reset TF Graph
tf.reset_default_graph()
sess = tf.Session()

# Load BaseModel
model = Deeplab_v3(input_type=model_type)
if model_type == 'rgbt':
    image = tf.placeholder(tf.float32, [None, 512, 512, 4], name='input_x')
else:
    image = tf.placeholder(tf.float32, [None, 512, 512, 3], name='input_x')
label = tf.placeholder(tf.int32, [None, 512, 512])
lr = tf.placeholder(tf.float32, )

logits = model.forward_pass(image)
logits_prob = tf.nn.softmax(logits=logits, name='logits_prob')
predicts = tf.argmax(logits, axis=-1, name='predicts')
restore_model(ckpt_path)

all_tests_result = {}
key_map = {'IOU_0': 0, 'IOU_1': 1, 'IOU_2': 2, 'IOU_3': 3, 'IOU_4': 4, 'IOU_5': 5}
with open(test_list_path, 'r') as f:
    reader = csv.reader(f, delimiter=',')
    for i, line in enumerate(reader):
        if i == 0:
            continue
        if model_type == 'rgbt':
            img_rgb = cv2.imread(line[0], cv2.IMREAD_COLOR)
            img_rgb = cv2.resize(img_rgb, (512, 512))
            img_thermal = cv2.resize(cv2.imread(line[1], 0), (512, 512)).reshape((512, 512, 1))
            img = np.concatenate((img_rgb, img_thermal), axis=2)
        else:
            img_rgb = cv2.imread(line[0], cv2.IMREAD_COLOR)
            img_rgb = cv2.resize(img_rgb, (512, 512))
            img = img_rgb
        test_predict = multi_scale_predict(
        	image=img,
        	input_placeholder=image,
        	is_training_placeholder=model._is_training,
            logits_prob_node=logits_prob,
            sess=sess,
            multi=False,
            size=512)
        g_truth = cv2.resize(np.array(Image.open(line[2])), (512, 512))
        result = iou(y_pre=np.reshape(test_predict, -1),
                     y_true=np.reshape(g_truth, -1))
        label_valid = np.unique(g_truth)
        for key in sorted(result.keys()):
            if key in key_map and not key_map[key] in label_valid:
                continue
            if np.isnan(result[key]) or result[key] != result[key]:
                continue
            if not key in all_tests_result:
                all_tests_result[key] = [result[key]]
            else:
                all_tests_result[key].append(result[key])
        test_label = color_predicts(img=g_truth)
        test_predict = color_predicts(img=test_predict)
        full_image = np.concatenate((img_rgb, test_label, test_predict), axis=1)
        out_name = line[0].split('/')[-1].split('.')[0]+'_predict.jpg'
        out_path = result_dir + '/' + out_name
        cv2.imwrite(out_path, full_image)
        print('Saved '+out_path)
avg_tests_result = {}
for key in sorted(all_tests_result.keys()):
    avg_tests_result[key] = sum(all_tests_result[key])/len(all_tests_result[key])
    offset = 40 - key.__len__()
    print(key + ' ' * offset + '%.4f' % avg_tests_result[key])


from threading import Thread
import time
import cv2

class VideoGet:

    def __init__(self, src=0):
        self.stream = cv2.VideoCapture(src)
        self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
        self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
        (self.grabbed, self.frame) = self.stream.read()
        self.stopped = False

    def start(self):
        Thread(target=self.get, args=()).start()
        return self

    def get(self):
        while not self.stopped:
            if not self.grabbed:
                self.stop()
                print("stopped")
            else:
                (self.grabbed, self.frame) = self.stream.read()
                time.sleep(0.01)

    def stop(self):
        self.stopped = True


#from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework import status

from .models import Relay
from .serializers import RelaySerializer

@api_view(['GET'])
@permission_classes((IsAuthenticated,))
def relays(request):
    if request.method == 'GET':
        relays_list = Relay.objects.filter(owner=request.user)
        serializer = RelaySerializer(relays_list, many=True)

        return Response(serializer.data)

@api_view(['GET', 'PUT', 'DELETE'])
@permission_classes((IsAuthenticated,))
def relay(request, pk):
    try:
        relay = Relay.objects.get(pk=pk)
    except Relay.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if relay.owner != request.user:
        return Response({'response': 'You do not have permissions for this action'})

    if request.method == 'GET':
        serializer = RelaySerializer(relay)
        return Response(serializer.data)
    elif request.method == 'PUT':
        serializer = RelaySerializer(relay, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(status=status.HTTP_404_NOT_FOUND)
    elif request.method == 'DELETE':
        relay.delete()
        return  Response(status=status.HTTP_204_NO_CONTENT)

@api_view(['POST'])
@permission_classes((IsAuthenticated,))
def new_relay(request):
    if request.method == 'POST':
        owner = Relay(owner=request.user)
        serializer = RelaySerializer(owner, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)