# Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>

# AnTOS Web desktop is is licensed under the GNU General Public
# License v3.0, see the LICENCE file for more information

# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of 
# the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.

# You should have received a copy of the GNU General Public License
#along with this program. If not, see https://www.gnu.org/licenses/.
class Blogger extends this.OS.GUI.BaseApplication
    constructor: (args) ->
        super "Blogger", args
    
    main: () ->
        me = @
        @tabbar = @find "tabbar"
        @containers = [
            @find("user-container"),
            @find("cv-container"),
            @find("blog-container")
        ]
        @user = {}
        @cvlist = @find "cv-list"
        @cvlist.set "ontreeselect", (d) ->
            me.CVSectionByCID Number(d.id)
        @inputtags = @.find "input-tags"
        @bloglist = @find "blog-list"
        @userdb = new @_api.DB("user")
        @cvcatdb = new @_api.DB("cv_cat")
        @cvsecdb = new @_api.DB("cv_sections")
        @blogdb = new @_api.DB("blogs")
        @tabbar.set "onlistselect", (e) ->
            ($ el).hide() for el in me.containers
            me.fetchData e.idx
            ($ me.containers[e.idx]).show()
            me.trigger "calibrate"

        @tabbar.set "items", [
            { iconclass: "fa fa-user-circle", selected: true },
            { iconclass: "fa fa-info-circle" },
            { iconclass: "fa fa-book" }
        ]
        (@find "bt-user-save").set "onbtclick", (e) ->
            me.saveUser()

        (@find "cv-cat-add").set "onbtclick", (e) ->
            me.openDialog "BloggerCategoryDialog",
            (d) ->
                c =
                    name: d.value,
                    pid: d.p.id,
                    publish: 1
                me.cvcatdb.save c, (r) ->
                    me.error __("Cannot add new category") if r.error
                    me.refreshCVCat()
                    #update the list

            , __("Add category"), { tree: me.cvlist.get "data" }
        
        (@find "cv-cat-edit").set "onbtclick", (e) ->
            cat = me.cvlist.get "selectedItem"
            return unless cat
            me.openDialog "BloggerCategoryDialog", (d) ->
                c =
                    id: cat.id,
                    publish: cat.publish,
                    pid: d.p.id,
                    name: d.value
                
                me.cvcatdb.save c, (r) ->
                    return me.error __("Cannot Edit category") if r.error
                    me.refreshCVCat()
            , __("Edit category"), { tree: (me.cvlist.get "data"), cat: cat }

        (@find "cv-cat-del").set "onbtclick", (e) ->
            cat = me.cvlist.get "selectedItem"
            return unless cat
            me.openDialog "YesNoDialog",
                (d) ->
                    return unless d
                    me.deleteCVCat cat
            , __("Delete category") ,
            { iconclass: "fa fa-question-circle", text: __("Do you really want to delete: {0}?", cat.name) }
    
        (@find "cv-sec-add").set "onbtclick", (e) ->
            cat = me.cvlist.get "selectedItem"
            return me.notify __("Please select a category") unless cat and cat.id isnt 0
            me.openDialog "BloggerCVSectionDiaglog", (d) ->
                d.cid = Number cat.id
                d.start = Number d.start
                d.end = Number d.end
                d.publish = 1
                me.cvsecdb.save d, (r) ->
                    return me.error __("Cannot save section: {0}", r.error) if r.error
                    me.CVSectionByCID Number(cat.id)

            , __("New section entry for {0}", cat.name), null

        (@find "cv-sec-move").set "onbtclick", (e) ->
            sec = (me.find "cv-sec-list").get "selected"
            return me.notify __("Please select a section to move") unless sec
            
            me.openDialog "BloggerCategoryDialog", (d) ->
                c =
                    id: sec.id,
                    cid: d.p.id
                
                me.cvsecdb.save c, (r) ->
                    return me.error __("Cannot move section") if r.error
                    me.CVSectionByCID(sec.cid)
                    (me.find "cv-sec-list").set "selected", -1
            , __("Move to"), { tree: (me.cvlist.get "data"), selonly: true }

        (@find "cv-sec-edit").set "onbtclick", (e) ->
            sec = (me.find "cv-sec-list").get "selected"
            return me.notify __("Please select a section to edit") unless sec
            
            me.openDialog "BloggerCVSectionDiaglog", (d) ->
                d.cid = Number sec.cid
                d.start = Number d.start
                d.end = Number d.end
                d.publish = Number sec.publish
                me.cvsecdb.save d, (r) ->
                    return me.error __("Cannot save section: {0}", r.error) if r.error
                    me.CVSectionByCID Number(sec.cid)

            , __("Modify section entry"), sec

        @editor = new SimpleMDE
            element: me.find "markarea"
            autofocus: true
            tabSize: 4
            indentWithTabs: true
            toolbar: [
                {
                    name: __("New"),
                    className: "fa fa-file",
                    action: (e) ->
                        me.bloglist.set "selected", -1
                        me.clearEditor()
                },
                {
                    name: __("Save"),
                    className: "fa fa-save",
                    action: (e) ->
                        me.saveBlog()
                }
                , "|", "bold", "italic", "heading", "|", "quote", "code",
                "unordered-list", "ordered-list", "|", "link",
                "image", "table", "horizontal-rule",
                {
                    name: "image",
                    className: "fa fa-file-image-o",
                    action: (e) ->
                        me.openDialog "FileDiaLog", (d, n, p) ->
                            p.asFileHandler().publish (r) ->
                                return me.error __("Cannot export file for embedding to text") if r.error
                                doc = me.editor.codemirror.getDoc()
                                doc.replaceSelection "![](#{me._api.handler.shared}/#{r.result})"
                        , __("Select image file"), { mimes: ["image/.*"] }
                },
                {
                    name:"Youtube",
                    className: "fa fa-youtube",
                    action: (e) ->
                        doc = me.editor.codemirror.getDoc()
                        doc.replaceSelection "[[youtube:]]"
                }
                "|",
                {
                    name: __("Preview"),
                    className: "fa fa-eye no-disable",
                    action: (e) ->
                        me.previewOn = !me.previewOn
                        SimpleMDE.togglePreview e
                }
            ]
        @bloglist.set "onlistselect", (e) ->
            sel = me.bloglist.get "selected"
            return unless sel
            me.blogdb.get Number(sel.id), (r) ->
                me.error __("Cannot fetch the entry content") if r.error
                me.editor.value atob(r.result.content)
                me.inputtags.value = r.result.tags
                (me.find "blog-publish").set "swon", (if Number(r.result.publish) then true else false)

        @.bloglist.set "onitemclose", (e) ->
            me.openDialog "YesNoDialog", (b) ->
                return unless b
                me.blogdb.delete e.item.item.id, (r) ->
                    return me.error __("Cannot delete: {0}", r.error) if r.error
                    me.bloglist.remove e.item.item, true
                    me.bloglist.set "selected", -1
                    me.clearEditor()
            ,  __("Delete a post") ,
            { iconclass: "fa fa-question-circle", text: __("Do you really want to delete this post ?") }
            return false
        @bindKey "CTRL-S", () ->
            sel = me.tabbar.get "selidx"
            return unless sel is 2
            me.saveBlog()
        @on "vboxchange", () ->
            me.resizeContent()
    # USER TAB
    fetchData: (idx) ->
        me = @
        switch idx
            when 0 #user info
                
                @userdb.get null, (d) ->
                    return me.error __("Cannot fetch user data") if d.error
                    me.user = d.result[0]
                    inputs = me.select "[input-class='user-input']"
                    ($ v).val me.user[v.name] for v in inputs
            when 1 # category
                @refreshCVCat()
            else 
                @loadBlogs()
    
    saveUser:() ->
        me = @
        inputs = @select "[input-class='user-input']"
        @user[v.name] = ($ v).val() for v in inputs
        return @notify __("Full name must be entered") if not @user.fullname or @user.fullname is ""
        #console.log @user
        @userdb.save @user, (r) ->
            return me.error __("Cannot save user data") if r.error
            return me.notify __("User data updated")


    # PORFOLIO TAB
    refreshCVCat: () ->
        me = @
        data =
            name: "Porfolio",
            id:0,
            nodes: []
        cnd =
            order:
                name: "ASC"
        @cvcatdb.find cnd, (d) ->
            if d.error
                me.cvlist.set "data", data
                return me.notify __("Cannot fetch CV categories")
            me.fetchCVCat d.result, data, "0"
            me.cvlist.set "data", data
            #it = (me.cvlist.find "pid", "2")[0]
            #me.cvlist.set "selectedItem", it

    fetchCVCat: (table, data, id) ->
        result = (v for v in table when v.pid is id)
        return data.nodes = null if result.length is 0
        for v in result
            v.nodes = []
            @fetchCVCat table, v, v.id
            #v.nodes = null if v.nodes.length is 0
            data.nodes.push v

    deleteCVCat: (cat) ->
        me = @
        ids = []
        func = (c) ->
            ids.push c.id
            func(v) for v in c.nodes if c.nodes
        func(cat)
        
        cond = ({ "=": { cid: v } } for v in ids)
        # delete all content
        @cvsecdb.delete { "or": cond }, (r) ->
            return me.error __("Cannot delete all content of: {0} [{1}]", cat.name, r.error) if r.error
            cond = ({ "=": { id: v } } for v in ids)
            me.cvcatdb.delete { "or": cond }, (re) ->
                return me.error __("Cannot delete the category: {0} [{1}]", cat.name, re.error) if re.error
                me.refreshCVCat()

    CVSectionByCID: (cid) ->
        me = @
        cond =
            exp:
                "=":
                    cid: cid
            order:
                start: "DESC"
        @cvsecdb.find cond, (d) ->
            return me.notify __("Section list is empty, please add one") if d.error
            v.text = v.title for v in d.result
            items = []
            $(me.find "cv-sec-status").html __("Found {0} sections", d.result.length)
            for  v in d.result
                v.text = v.title
                v.complex = true
                v.start = Number(v.start)
                v.end = Number(v.end)
                v.detail = []
                v.detail.push { text: v.subtitle, class: "cv-subtitle" } if v.subtitle isnt ""
                if v.start isnt 0 and v.end isnt 0
                    v.detail.push { text: "#{v.start} - #{v.end}", class: "cv-period" } 
                else
                    v.detail.push { text: "", class: "cv-period" }
                v.detail.push { text: v.location, class: "cv-loc" } if v.location isnt ""
                #v.detail.push { text: v.end } if v.end isnt 0
                v.closable = true
                v.detail.push { text: v.content, class: "cv-content" }
                items.push v
            el = me.find "cv-sec-list"
            el.set "onitemclose", (e) ->
                me.openDialog "YesNoDialog", (b) ->
                    return unless b
                    me.cvsecdb.delete e.item.item.id, (r) ->
                        return me.error __("Cannot delete the section: {0}", r.error) if r.error
                        el.remove e.item.item, true
                ,  __("Delete section") ,
                { iconclass: "fa fa-question-circle", text: __("Do you really want to delete: {0}?",e.item.item.text) }
                return false
            el.set "items", items

    # blog
    saveBlog: () ->
        me = @
        sel = @bloglist.get "selected"
        tags = @inputtags.value
        content = @editor.value()
        title = (new RegExp "^#+(.*)\n", "g").exec content
        return @notify __("Please insert a title in the text: beginning with heading") unless title and title.length is 2
        return @notify __("Please enter tags") if tags is ""
        d = new Date()
        data =
            content: content.asBase64()
            title: title[1].trim()
            tags: tags
            ctime: if sel then sel.ctime else d.timestamp()
            ctimestr: if sel then sel.ctimestr else d.toString()
            utime: d.timestamp()
            utimestr: d.toString()
            rendered: me.process(me.editor.options.previewRender(content))
            publish: if ((@find "blog-publish").get "swon") then 1 else 0
        data.id = sel.id if sel
        #save the data
        @blogdb.save data, (r) ->
            return me.error __("Cannot save blog: {0}", r.error) if r.error
            me.loadBlogs()
    
    process: (text) ->
        # find video tag and rendered it
        embed = (id) ->
            return """
                <iframe
                    class = "embeded-video"
                    width="560" height="315" 
                    src="https://www.youtube.com/embed/#{id}"
                    frameborder="0" allow="encrypted-media" allowfullscreen
                ></iframe>
            """
        re  = /\[\[([^:]*):([^\]]*)\]\]/g
        replace = []
        while (found = re.exec text) isnt null
            replace.push found
        return text.asBase64() unless replace.length > 0
        ret = ""
        begin = 0
        for it in replace
            ret += text.substring begin, it.index
            ret += embed(it[2])
            begin = it.index + it[0].length
        ret += text.substring begin, text.length
        #console.log ret
        return ret.asBase64()
        
    clearEditor:() ->
        @.editor.value ""
        @.inputtags.value = ""
        (@.find "blog-publish").set "swon", false
    # load blog
    loadBlogs: () ->
        me = @
        selidx = @bloglist.get "selidx"
        cond =
            order:
                ctime: "DESC"
            fields: [
                "id",
                "title",
                "ctimestr",
                "ctime",
                "utime",
                "utimestr"
            ]
        @blogdb.find cond, (r) ->
            return me.notify __("No post found: {0}", r.error) if r.error
            for v in r.result
                v.text = v.title
                v.complex = true
                v.closable = true
                v.detail = [
                    { text: __("Created: {0}", v.ctimestr), class: "blog-dates" },
                    { text: __("Updated: {0}", v.utimestr), class: "blog-dates" }]
            me.bloglist.set "items", r.result
            if selidx isnt -1
                me.bloglist.set "selected", selidx
            else
                me.clearEditor()
                me.bloglist.set "selected", -1
    resizeContent: () ->
        container = @find "editor-container"
        children = ($ container).children()
        titlebar = (($ @scheme).find ".afx-window-top")[0]
        toolbar = children[1]
        statusbar = children[4]
        cheight = ($ @scheme).height() - ($ titlebar).height() - ($ toolbar).height() - ($ statusbar).height() - 90
        ($ children[2]).css("height", cheight + "px")
Blogger.singleton = true
Blogger.dependencies = [ "mde/simplemde.min" ]
this.OS.register "Blogger", Blogger