class OpenPage extends this.OS.GUI.BaseApplication
    constructor: ( args ) ->
        super "OpenPage", args
    
    main: () ->
        # load session class
        #if not OpenPage.EditorSession
        #    require ["webodf/editor/EditorSession"], (ES) ->
        #        OpenPage.EditorSession = ES
        me =@
        @eventSubscriptions = new core.EventSubscriptions()
        @initToolbox()
        @userid = "#{@systemsetting.user.username}@#{@pid}"
        #file = "home://welcome.odt"
        #file = "#{@_api.handler.get}/home://welcome.odt"
        #@canvas.load file
        #odfContainer = new odf.OdfContainer file, (c) ->
        #    me.canvas.setOdfContainer c, false
        @currentStyle = ""
        if @args and @args.length > 0 then @open @args[0] else @newdoc()
        @resource =
            fonts: []
            formats: []
        @bindKey "ALT-N", () -> me.actionFile "#{me.name}-New"
        @bindKey "ALT-O", () -> me.actionFile "#{me.name}-Open"
        @bindKey "CTRL-S", () -> me.actionFile "#{me.name}-Save"
        @bindKey "ALT-W", () -> me.actionFile "#{me.name}-Saveas"
        
    
    menu: () ->
        me = @
        menu = [{
                text: "__(File)",
                child: [
                    { text: "__(New)", dataid: "#{@name}-New", shortcut: "A-N" },
                    { text: "__(Open)", dataid: "#{@name}-Open", shortcut: "A-O" },
                    { text: "__(Save)", dataid: "#{@name}-Save", shortcut: "C-S" },
                    { text: "__(Save as)", dataid: "#{@name}-Saveas", shortcut: "A-W" }
                ],
                onmenuselect: (e) -> me.actionFile e.item.data.dataid
            }]
        menu
    
    actionFile: (e) ->
        me = @
        saveas = () ->
            me.openDialog "FileDiaLog", (d, n, p) ->
                me.currfile.setPath "#{d}/#{n}"
                me.save()
            , __("Save as"), { file: me.currfile }
        switch e
            when "#{@name}-Open"
                @openDialog "FileDiaLog", ( d, f , p) ->
                    me.open p
                , __("Open file"), { mimes: me.meta().mimes }
            when "#{@name}-Save"
                #@currfile.cache = @editor.value()
                return @save() if @currfile.basename
                saveas()
            when "#{@name}-Saveas"
                saveas()
             when "#{@name}-New"
                @newdoc()
    
    
    newdoc: () ->
        blank = "#{@meta().path}/blank.odt"
        @open blank, true
    open: (p,b) ->
        me = @
        @pathAsDataURL(p)
            .then (r) ->
                me.closeDocument() if me.editorSession
                me.initCanvas()
                OdfContainer = new odf.OdfContainer r.data, (c) ->
                    me.canvas.setOdfContainer c, false
                    return me.currfile  = "Untitled".asFileHandler() if b
                    if me.currfile then me.currfile.setPath p else me.currfile = p.asFileHandler()
                    me.scheme.set "apptitle", me.currfile.basename
                    me.notify __("File {0} opened", p)
            .catch (e) ->
                me.error __("Problem read file {0}", e) 
    
    save: () ->
        me = @
        return unless @editorSession
        container = @canvas.odfContainer()
        return @error __("No document container found") unless container
        container.createByteArray (ba) ->
            # create blob
            me.currfile.cache = new Blob [ba], { type: "application/vnd.oasis.opendocument.text" }
            me.currfile.write "application/vnd.oasis.opendocument.text", (r) ->
                return me.error __("Cannot save file: {0}", r.error) if r.error
                me.notify __("File {0} saved", me.currfile.basename)
                me.scheme.set "apptitle", me.currfile.basename
                me.currfile.dirty = false
                me.editorFocus()
        , (err) ->
            @error __("Cannot create byte array from container: {0}", err|| "")
    
    initToolbox: () ->
        me = @
        @basictool =
            undo: @find("btundo"),
            redo: @find("btredo"),
            bold: @find("btbold"),
            italic:@find("btitalic"),
            underline:@find("btunderline"),
            strike: @find("btstrike"),
            note: @find("btnote"),
            link: @find("btlink"),
            unlink: @find("btunlink"),
            image:@find("btimage"),
            ac: @find("btac"),
            al: @find("btal"),
            ar: @find("btar"),
            aj: @find("btaj"),
            indent: @find("btindent"),
            outdent: @find("btoutdent"),
            fonts: @find("font-list"),
            fontsize: @find("font-size"),
            styles: @find("format-list"),
            zoom: @find("slzoom")
            format: @find("btformat")
        
        fn = (name, el) ->
            if name is "fonts" or name is "styles"
               act = "onlistselect"
            else if name is "fontsize" or name is "zoom"
                act = "onchange"
            else
                act = "onbtclick"
            el.set act, (e) ->
                return unless me.directFormattingCtl
                return unless me[name]
                me[name](e)
                me.editorFocus()
        for name, el of @basictool
           fn name, el
        
        (@find "btzoomfix").set "onbtclick", (e) -> me.zoom 100
        @basictool.zoom.set "onchanging", (e) ->
            zlb = me.find "lbzoom"
            zlb.set "text", Math.floor(e) + "%"
        
    initCanvas: () ->
        el = @find "odfcanvas"
        me = @
        el.setAttribute "translate", "no"
        el.classList.add "notranslate"
        @canvas = new odf.OdfCanvas(el)
        @documentChanged = (e) ->
            return if me.currfile.dirty
            me.currfile.dirty = true
            me.scheme.set "apptitle", me.currfile.basename + "*"
            #console.log e
        @metaChanged = (e) ->
            return if me.currfile.dirty
            me.currfile.dirty = true
            me.scheme.set "apptitle", me.currfile.basename + "*"
            #console.log e
        @textStylingChanged = (e) ->
            me.updateToolbar e
        @paragrahStyleChanged = (e) ->
            return unless e.type is "style"
            items = me.basictool.styles.get "items"
            item = i for v, i in items when v.name is e.styleName
            me.currentStyle = e.styleName
            me.basictool.styles.set "selected", item
        
        @styleAdded = (e) ->
            return unless e.family is 'paragraph'
            items = me.basictool.styles.get "items"
            item = v for v in items when v.name is e.name
            return if item
            stylens = "urn:oasis:names:tc:opendocument:xmlns:style:1.0"
            el = me.editorSession.getParagraphStyleElement e.name
            dtext = el.getAttributeNS stylens, 'display-name'
            me.basictool.styles.push { text: dtext , name: e.name }, true
            #me.resource.formats.push {text: dtext, name:e.name}
        
        @updateSlider = (v) ->
            value = Math.floor v*100
            me.basictool.zoom.set "value", value
            zlb = me.find "lbzoom"
            zlb.set "text", value+"%"
        #me.canvas.enableAnnotations true, true
        @canvas.addListener "statereadychange", ()->
            me.session = new ops.Session(me.canvas)
            viewOptions =
                editInfoMarkersInitiallyVisible: false,
                caretAvatarsInitiallyVisible: false,
                caretBlinksOnRangeSelect: true
            
            me.editorSession = new OpenPage.EditorSession(me.session,me.userid, {
                viewOptions: viewOptions,
                directTextStylingEnabled: true,
                directParagraphStylingEnabled: true,
                paragraphStyleSelectingEnabled: true,
                paragraphStyleEditingEnabled: true,
                imageEditingEnabled: true,
                hyperlinkEditingEnabled: true,
                annotationsEnabled: true,
                zoomingEnabled: true,
                reviewModeEnabled: false
            })
            me.initFontList me.editorSession.getDeclaredFonts()
            me.initStyles me.editorSession.getAvailableParagraphStyles()
            #fix annotation problem on canvas
            #console.log $("office:body").css "background-color", "red"
            # basic format
            me.directFormattingCtl = me.editorSession.sessionController.getDirectFormattingController()
            me.directFormattingCtl.subscribe gui.DirectFormattingController.textStylingChanged, me.textStylingChanged
            me.directFormattingCtl.subscribe gui.DirectFormattingController.paragraphStylingChanged, me.textStylingChanged
            me.editorSession.subscribe OpenPage.EditorSession.signalParagraphChanged, me.paragrahStyleChanged
            
            # hyper link controller
            me.hyperlinkController = me.editorSession.sessionController.getHyperlinkController()
            me.eventSubscriptions.addFrameSubscription me.editorSession, OpenPage.EditorSession.signalCursorMoved, ()-> me.updateHyperlinkButtons()
            me.eventSubscriptions.addFrameSubscription me.editorSession, OpenPage.EditorSession.signalParagraphChanged, ()-> me.updateHyperlinkButtons()
            me.eventSubscriptions.addFrameSubscription me.editorSession, OpenPage.EditorSession.signalParagraphStyleModified, ()-> me.updateHyperlinkButtons()
            
            #annotation controller
            me.annotationController = me.editorSession.sessionController.getAnnotationController()
            
            #image controller
            me.imageController = me.editorSession.sessionController.getImageController()
            #imageController.subscribe(gui.ImageController.enabledChanged, enableButtons)
            
            #text controller
            me.textController = me.editorSession.sessionController.getTextController()
            
            # zoom controller
            me.zoomHelper = me.editorSession.getOdfCanvas().getZoomHelper()
            me.zoomHelper.subscribe gui.ZoomHelper.signalZoomChanged, me.updateSlider
            me.updateSlider me.zoomHelper.getZoomLevel()
            
            # format controller 
            me.editorSession.subscribe OpenPage.EditorSession.signalCommonStyleCreated, me.styleAdded
            
            me.editorSession.sessionController.setUndoManager new gui.TrivialUndoManager()
            me.editorSession.sessionController.getUndoManager().subscribe gui.UndoManager.signalDocumentModifiedChanged, me.documentChanged
            me.editorSession.sessionController.getMetadataController().subscribe gui.MetadataController.signalMetadataChanged, me.metaChanged
            op = new ops.OpAddMember()
            op.init {
                memberid: me.userid,
                setProperties:{
                    "fullName": me.userid,
                    "color": "blue"
                }
            }
            me.session.enqueue([op])
            me.editorSession.sessionController.insertLocalCursor()
            me.editorSession.sessionController.startEditing()
            #console.log me.editorSession.getDeclaredFonts()
            #
    
    initFontList: (list) ->
        v.text = v.name for v in list
        @resource.fonts.push { text: v.text, name: v.family } for v in list
        @basictool.fonts.set "items", list
    
    initStyles: (list) ->
        list.unshift {name:"", displayName: 'Default style' }
        v.text = v.displayName for v in list
        @resource.formats.push { text: v.text, name: v.name } for v in list
        @basictool.styles.set "items", list
    
    updateToolbar: (changes) ->
        # basic style
        (@basictool.bold.set "selected", changes.isBold) if changes.hasOwnProperty 'isBold'
        (@basictool.italic.set "selected", changes.isItalic) if changes.hasOwnProperty 'isItalic'
        (@basictool.underline.set "selected", changes.hasUnderline) if changes.hasOwnProperty 'hasUnderline'
        (@basictool.strike.set "selected", changes.hasStrikeThrough) if changes.hasOwnProperty 'hasStrikeThrough'
        (@basictool.fontsize.set "value", changes.fontSize) if changes.hasOwnProperty "fontSize"
        @selectFont changes.fontName if changes.hasOwnProperty "fontName"
        #pharagraph style
        @basictool.al.set "selected", changes.isAlignedLeft if changes.hasOwnProperty "isAlignedLeft"
        @basictool.ar.set "selected", changes.isAlignedRight if changes.hasOwnProperty "isAlignedRight"
        @basictool.ac.set "selected", changes.isAlignedCenter if changes.hasOwnProperty "isAlignedCenter"
        @basictool.aj.set "selected", changes.isAlignedJustified if changes.hasOwnProperty "isAlignedJustified"
    
    updateHyperlinkButtons: (e) ->
        selectedLinks = @editorSession.getSelectedHyperlinks()
        @basictool.unlink.set "enable", selectedLinks.length > 0
    
    selectFont: (name) ->
        items = @basictool.fonts.get "items"
        item = i for v, i in items when v.name is name
        @basictool.fonts.set "selected", item
    
    editorFocus: () ->
        @editorSession.sessionController.getEventManager().focus()
        
    bold: (e) ->
        #console.log @, e
        @directFormattingCtl.setBold (not @basictool.bold.get "selected")
    
    italic: (e) ->
        @directFormattingCtl.setItalic (not @basictool.italic.get "selected")
    
    underline: (e) ->
        @directFormattingCtl.setHasUnderline (not @basictool.underline.get "selected")
    
    strike: (e) ->
        @directFormattingCtl.setHasStrikethrough (not @basictool.strike.get "selected")
    
    fonts: (e) ->
        @directFormattingCtl.setFontName e.data.name
    
    fontsize: (e) ->
        @directFormattingCtl.setFontSize e
    
    al: (e) ->
        @directFormattingCtl.alignParagraphLeft()
    
    ar: (e) ->
        @directFormattingCtl.alignParagraphRight()
    
    ac: (e) ->
        @directFormattingCtl.alignParagraphCenter()
    
    note: (e) ->
        @annotationController.addAnnotation()
    
    aj: (e) ->
        @directFormattingCtl.alignParagraphJustified()
    
    indent: (e) ->
        @directFormattingCtl.indent()
    
    outdent: (e) ->
        @directFormattingCtl.outdent()
    
    link: (e) ->
        # get the link first
        me = @
        textSerializer = new odf.TextSerializer()
        selection = @editorSession.getSelectedRange()
        linksInSelection = @editorSession.getSelectedHyperlinks()
        linkTarget = if linksInSelection[0] then odf.OdfUtils.getHyperlinkTarget(linksInSelection[0]) else "http://"
        data =
            link: linkTarget,
            text: "",
            readonly: true,
            action: "new"
        if selection and selection.collapsed and linksInSelection.length == 1
            # selection is collapsed within a single link
            # text in this case is read only
            data.text = textSerializer.writeToString linksInSelection[0]
            data.action = "edit"
        else if selection and !selection.collapsed
            # user select part of link or a block of text
            # user convert a selection to a link
            data.text = textSerializer.writeToString selection.cloneContents()
        else
            data.readonly = false
        @openDialog new HyperLinkDialog(), (d) ->
            selectionController = me.editorSession.sessionController.getSelectionController()
            if d.readonly
                # edit the existing link
                if d.action is "edit"
                    selectedLinkRange = selection.cloneRange()
                    selectedLinkRange.selectNode(linksInSelection[0])
                    selectionController.selectRange(selectedLinkRange, true)
                me.hyperlinkController.removeHyperlinks()
                me.hyperlinkController.addHyperlink d.link
            else
                me.hyperlinkController.addHyperlink d.link, d.text
                linksInSelection = me.editorSession.getSelectedHyperlinks()
                selectedLinkRange = selection.cloneRange()
                selectedLinkRange.selectNode(linksInSelection[0])
                selectionController.selectRange(selectedLinkRange, true)
        , "__(Insert/edit link)", data
    
    unlink: (e) ->
        @hyperlinkController.removeHyperlinks()
    
    undo: (e) ->
        @editorSession.undo()
    
    redo: (e) ->
        @editorSession.redo()
    
    pathAsDataURL: (p) ->
        return new Promise (resolve, error) ->
            fp = p.asFileHandler()
            fp.read (data) ->
                blob = new Blob [data], { type: fp.info.mime }
                reader = new FileReader()
                reader.onloadend = () ->
                    return error(p) if reader.readyState isnt 2
                    resolve {data: reader.result, fp: fp }
                reader.readAsDataURL blob
            , "binary"
            ###
            if not isText
                
            else
                fp.read (data) ->
                    # convert to base64
                    b64 = btoa data
                    dataurl = "data:#{fp.info.mime};base64," + b64
                    resolve { reader: {result: dataurl}, fp:fp }
            ###
    
    image: (e) ->
        me = @
        @openDialog "FileDiaLog", (d, n, p) ->
            me.pathAsDataURL(p)
                .then (r) ->
                    hiddenImage = new Image()
                    hiddenImage.style.position = "absolute"
                    hiddenImage.style.left = "-99999px"
                    document.body.appendChild hiddenImage
                    hiddenImage.onload =  () ->
                        content = r.data.substring(r.data.indexOf(",") + 1)
                        #insert image
                        me.textController.removeCurrentSelection()
                        me.imageController.insertImage r.fp.info.mime, content, hiddenImage.width, hiddenImage.height
                        document.body.removeChild hiddenImage
                    hiddenImage.src = r.data
                .catch () ->
                    me.error __("Couldnt load image {0}", p)
        , __("Select image file"), { mimes: ["image/.*"] }
    
    styles: (e) ->
        return if e.data.name is @currentStyle
        @editorSession.setCurrentParagraphStyle e.data.name
    
    zoom: (e) ->
        #console.log "zooming", e
        return unless @zoomHelper
        @zoomHelper.setZoomLevel e/100.0
    
    format: (e) ->
        @openDialog new FormatDialog(), (d) ->
                return
        , __("Add/Modify paragraph format"), @resource
    
    closeDocument: (f) ->
        # finish editing
        return unless @editorSession and @session
        me = @
        @eventSubscriptions.unsubscribeAll()
        @editorSession.sessionController.endEditing()
        @editorSession.sessionController.removeLocalCursor()
        # remove user
        op = new ops.OpRemoveMember()
        op.init {
            memberid: @userid
        }
        @session.enqueue [op]
        # close the session
        @session.close (e) ->
            return me.error __("Cannot close session {0}", e) if e
            me.editorSession.sessionController.getMetadataController().unsubscribe gui.MetadataController.signalMetadataChanged, me.metaChanged
            me.editorSession.sessionController.getUndoManager().unsubscribe gui.UndoManager.signalDocumentModifiedChanged, me.documentChanged
            me.directFormattingCtl.unsubscribe gui.DirectFormattingController.textStylingChanged, me.textStylingChanged
            me.directFormattingCtl.unsubscribe gui.DirectFormattingController.paragraphStylingChanged, me.textStylingChanged
            me.editorSession.unsubscribe OpenPage.EditorSession.signalParagraphChanged, me.paragrahStyleChanged
            me.zoomHelper.unsubscribe gui.ZoomHelper.signalZoomChanged, me.updateSlider
            me.editorSession.unsubscribe OpenPage.EditorSession.signalCommonStyleCreated, me.styleAdded
            # destry editorSession
            me.editorSession.destroy (e) ->
                return me.error __("Cannot destroy editor session {0}", e) if e
                me.editorSession = undefined
                # destroy session
                me.session.destroy (e) ->
                    return me.error __("Cannot destroy document session {0}", e) if e
                    core.Async.destroyAll [me.canvas.destroy], (e) ->
                        return me.error __("Cannot destroy canvas {0}", e) if e
                        me.notify "Document closed"
                        f() if f
                    me.session = undefined
                    me.annotationController = undefined
                    me.directFormattingCtl = undefined
                    me.textController = undefined
                    me.imageController = undefined
                    me.ZoomHelper = undefined
                    me.metaChanged = undefined
                    me.documentChanged = undefined
                    me.textStylingChanged = undefined
                    me.paragrahStyleChanged = undefined
                    me.updateSlider = undefined
                    me.styleAdded = undefined
                    me.basictool.fonts.set "selected", -1
                    me.basictool.styles.set "selected", -1
                    
                    #
            
    
    cleanup: (e) ->
        me = @
        if @editorSession
            e.preventDefault()
            me.closeDocument ()->
                me.quit()

this.OS.register "OpenPage", OpenPage