local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Event = require("ui/event")
local Screen = require("device").screen
local LeftContainer = require("ui/widget/container/leftcontainer")
local RightContainer = require("ui/widget/container/rightcontainer")
local FrameContainer = require("ui/widget/container/framecontainer")
local VerticalGroup = require("ui/widget/verticalgroup")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local BBoxWidget = require("ui/widget/bboxwidget")
local HorizontalSpan = require("ui/widget/horizontalspan")
local Button = require("ui/widget/button")
local Math = require("optmath")
local Blitbuffer = require("ffi/blitbuffer")

local PageCropDialog = VerticalGroup:new{
    ok_text = "OK",
    cancel_text = "Cancel",
    ok_callback = function() end,
    cancel_callback = function() end,
    button_width = math.floor(Screen:scaleBySize(70)),
}

function PageCropDialog:init()
    local horizontal_group = HorizontalGroup:new{}
    local ok_button = Button:new{
        text = self.ok_text,
        callback = self.ok_callback,
        width = self.button_width,
        bordersize = 2,
        radius = 7,
        text_font_face = "cfont",
        text_font_size = 20,
        show_parent = self,
    }
    local cancel_button = Button:new{
        text = self.cancel_text,
        callback = self.cancel_callback,
        width = self.button_width,
        bordersize = 2,
        radius = 7,
        text_font_face = "cfont",
        text_font_size = 20,
        show_parent = self,
    }
    local ok_container = RightContainer:new{
        dimen = Geom:new{ w = Screen:getWidth()*0.33, h = Screen:getHeight()/12},
        ok_button,
    }
    local cancel_container = LeftContainer:new{
        dimen = Geom:new{ w = Screen:getWidth()*0.33, h = Screen:getHeight()/12},
        cancel_button,
    }
    table.insert(horizontal_group, ok_container)
    table.insert(horizontal_group, HorizontalSpan:new{ width = Screen:getWidth()*0.34})
    table.insert(horizontal_group, cancel_container)
    self[2] = FrameContainer:new{
        horizontal_group,
        background = Blitbuffer.COLOR_WHITE,
        bordersize = 0,
        padding = 0,
    }
end

function PageCropDialog:onCloseWidget()
    UIManager:setDirty(nil, function()
        return "partial", self[1].dimen:combine(self[2].dimen)
    end)
    return true
end

function PageCropDialog:onShow()
    UIManager:setDirty(self, function()
        return "ui", self[1].dimen:combine(self[2].dimen)
    end)
    return true
end


local ReaderCropping = InputContainer:new{}

function ReaderCropping:onPageCrop(mode)
    self.ui:handleEvent(Event:new("CloseConfigMenu"))
    -- backup original zoom mode as cropping use "page" zoom mode
    self.orig_zoom_mode = self.view.zoom_mode
    if mode == "auto" then
        if self.document.configurable.text_wrap ~= 1 then
            self:setCropZoomMode(true)
        end
        return
    end
    -- backup original view dimen
    self.orig_view_dimen = Geom:new{w = self.view.dimen.w, h = self.view.dimen.h}
    -- backup original view bgcolor
    self.orig_view_bgcolor = self.view.outer_page_color
    self.view.outer_page_color = Blitbuffer.COLOR_GREY
    -- backup original page scroll
    self.orig_page_scroll = self.view.page_scroll
    self.view.page_scroll = false
    -- backup and disable original hinting state
    self.ui:handleEvent(Event:new("DisableHinting"))
    -- backup original reflow mode as cropping use non-reflow mode
    self.orig_reflow_mode = self.document.configurable.text_wrap
    if self.orig_reflow_mode == 1 then
        self.document.configurable.text_wrap = 0
        -- if we are in reflow mode, then we are already in page
        -- mode, just force readerview to recalculate visible_area
        self.view:recalculate()
    else
        self.ui:handleEvent(Event:new("SetZoomMode", "page", "cropping"))
    end
    self.ui:handleEvent(Event:new("SetDimensions",
        Geom:new{w = Screen:getWidth(), h = Screen:getHeight()*11/12})
    )
    self.bbox_widget = BBoxWidget:new{
        crop = self,
        ui = self.ui,
        view = self.view,
        document = self.document,
    }
    self.crop_dialog = PageCropDialog:new{
        self.bbox_widget,
        ok_callback = function() self:onConfirmPageCrop() end,
        cancel_callback = function() self:onCancelPageCrop() end,
    }
    UIManager:show(self.crop_dialog)
    return true
end

function ReaderCropping:onConfirmPageCrop()
    --DEBUG("new bbox", new_bbox)
    UIManager:close(self.crop_dialog)
    local new_bbox = self.bbox_widget:getModifiedPageBBox()
    self.ui:handleEvent(Event:new("BBoxUpdate", new_bbox))
    local pageno = self.view.state.page
    self.document.bbox[pageno] = new_bbox
    self.document.bbox[Math.oddEven(pageno)] = new_bbox
    self:exitPageCrop(true)
    return true
end

function ReaderCropping:onCancelPageCrop()
    UIManager:close(self.crop_dialog)
    self:exitPageCrop(false)
    return true
end

function ReaderCropping:exitPageCrop(confirmed)
    -- restore hinting state
    self.ui:handleEvent(Event:new("RestoreHinting"))
    -- restore page scroll
    self.view.page_scroll = self.orig_page_scroll
    -- restore view bgcolor
    self.view.outer_page_color = self.orig_view_bgcolor
    -- restore reflow mode
    self.document.configurable.text_wrap = self.orig_reflow_mode
    -- restore view dimens
    self.ui:handleEvent(Event:new("RestoreDimensions", self.orig_view_dimen))
    self.view:recalculate()
    -- Exiting should have the same look and feel with entering.
    if self.orig_reflow_mode == 1 then
        self.ui:handleEvent(Event:new("RestoreZoomMode"))
    else
        self:setCropZoomMode(confirmed)
    end
end

function ReaderCropping:setCropZoomMode(confirmed)
    if confirmed then
        -- if original zoom mode is not "content", set zoom mode to "contentwidth"
        self:setZoomMode(
            self.orig_zoom_mode:find("content")
            and self.orig_zoom_mode
            or "contentwidth")
        self.ui:handleEvent(Event:new("InitScrollPageStates"))
    else
        self:setZoomMode(self.orig_zoom_mode)
    end
end

function ReaderCropping:setZoomMode(mode)
    self.ui:handleEvent(Event:new("SetZoomMode", mode))
end

function ReaderCropping:onReadSettings(config)
    self.document.bbox = config:readSetting("bbox")
end

function ReaderCropping:onSaveSettings()
    self.ui.doc_settings:saveSetting("bbox", self.document.bbox)
end

return ReaderCropping
