say_widget = say_widget or {}

say_widget.global_say_sound = nil
say_widget.say_timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().GetTimer(_T("qe_level")).AttachTimer(_T("")))
say_widget.after_sound_delay = 900
say_widget.allow_koef_close = false
say_widget.letters_koef = 40
say_widget.allow_sound_close = false


__inherite(say_widget, null_lua_widget_handler())

function say_widget.__CreateInstance()
    return "say_widget"
end

say_widget.click_result = nil

function say_widget.StopSaySound()
    if say_widget.global_say_sound ~= nil then
        sf.core.g_Application.GetAudioManager().Stop(say_widget.global_say_sound, 0)
        say_widget.global_say_sound = nil
    end
end

function say_widget.ShowSay(_value)
    if quest.say_lua_widget then
        set_widget_flag_value(quest.say_lua_widget, sf.gui.CBaseWidget.FlagHidden, not _value)  
        set_widget_flag_value(quest.say_lua_widget, sf.gui.CBaseWidget.FlagDisabled, not _value)  
    end
end

local function say_mouse_event_impl(_this, _pos, _button, _state, _broadcast, _type)
    quest.global_say_window_result = 0
    say_widget.StopSaySound()
    local scene_offset = quest.global_current_main_scene.GetOffset()
    say_widget.click_result = {_pos - scene_offset, _button, _state, _broadcast, type = _type}
    local say_size = say_widget.say_area_info.size  
    local say_offset = say_widget.say_area_info.offset
    if (say_offset.X < _pos.X) and (say_offset.Y < _pos.Y) and (_pos.X < say_size.X + say_offset.X) and (_pos.Y < say_size.Y + say_offset.Y) then
        say_widget.click_result = nil
    end

end

function say_widget.OnMouseMove(_this, _pos, _state, _broadcast)
    local say_size = say_widget.say_area_info.size  
    local say_offset = say_widget.say_area_info.offset
    if (say_offset.X < _pos.X) and (say_offset.Y < _pos.Y) and (_pos.X < say_size.X + say_offset.X) and (_pos.Y < say_size.Y + say_offset.Y) then
        if quest.global_played_level then 
            quest.global_played_level.UpdateFocusedObject(nil) 
        end 
        return true
    end
    return false
end

function say_widget.OnMouseUp(_this, _pos, _button, _state, _broadcast)
    if quest.global_cursor.GetIsDrag() == true then
        say_mouse_event_impl(_this, _pos, _button, _state, _broadcast, "up")
    end
    return false
end

function say_widget.OnMouseDown(_this, _pos, _button, _state, _broadcast)
    say_mouse_event_impl(_this, _pos, _button, _state, _broadcast, "down")
    return false
end

function say_widget.OnDoubleClick(_this, _pos, _state, _broadcast)
    quest.global_say_window_result = 0
    say_widget.StopSaySound()
    return true
end


-------------------

function quest.OnOpenSay(_is_sound)
end

function quest.OnCloseSay(_is_sound)
end


function say_widget.pre_say(_say_text, _object, _offsetx, _offsety, _do_not_modify)
    say_widget.say(_say_text, _object, _offsetx, _offsety, _do_not_modify, true)
end

function say_widget.say(_say_text, _object, _offsetx, _offsety, _do_not_modify, _show_lips)
    if _say_text == nil or _say_text == "" then
        return
    end
    commit_score()
    if quest.global_skip_windows_flag == true then
        return false
    end

    if not _do_not_modify then
        quest.global_modify_level_flag = true 
    end

    local avatart_say = false
    if _object == nil or type(_object) ~= "string" then
        if _object ~= false then
            avatart_say = true
            --avatar_widget.avatar_say = true
            avatar_widget.SetAvatarSay(true)
        end
        _object = nil
    end

    say_widget.say_area_info = say_widget.form_say_widget(quest.say_lua_widget, _say_text, _object, _offsetx, _offsety)
    if say_widget.say_area_info ~= nil then

        say_widget.click_result = nil

        quest.global_say_window_result = nil

        --quest.global_played_level.SetHintText(_T(""))
        quest.global_cursor.SetHintText(_T(""), false)

        quest.do_not_change_curosor = true
        
        if not _show_lips then
            quest.allow_game_cursor = true 
        end

        
        cursor_lua_widget.DropCursor()
        cursor_lua_widget.DropGameCursor()

        if _show_lips then
            cursor_lua_widget.SetSayCursor(true)   
        end


        
        say_widget.ShowSay(true)

        local text_type = type(_say_text)
        local sound_string = nil
        say_widget.global_say_sound = nil
        local is_sound = false
        local sound_time = 0
        if text_type == "number" then
            sound_string = "say_"..tostring(_say_text)
            if sf.core.g_Application.GetAudioManager().IsSound(sound_string) then
                say_widget.global_say_sound = sf.core.g_Application.GetAudioManager().Play(sound_string, -2, -2, -2, -2, -2);
                sound_time = sf.core.g_Application.GetAudioManager().GetLength(sound_string)
                is_sound = true
            end
        end
        local say_time = nil
        if sound_time > 0 and say_widget.allow_sound_close and _show_lips then
            say_time = sound_time + say_widget.after_sound_delay 
        end
        if not say_time and say_widget.allow_koef_close and _show_lips then
            local text = _say_text
            if type(text) == "number" then
                text = sf.misc.g_StringTable.Instance().FormatByStringsID("$"..tostring(_say_text))
            end

            say_time = string.len (tostring(text)) * say_widget.letters_koef + say_widget.after_sound_delay 
        end

        if say_time then
            say_widget.say_timer.Get().SetTime(0)
        end
        quest.OnOpenSay(is_sound)
        local time = say_widget.say_timer.Get().GetTime()
        while true do
            if quest.global_say_window_result ~= nil or (say_time and time > say_time )then
                break
            end
            sleep(100)
            if say_time then
                time = say_widget.say_timer.Get().GetTime()
            end
        end
        quest.OnCloseSay(is_sound)
        say_widget.ShowSay(false)
        quest.global_say_momental_end_flag = true

        if _show_lips then
            cursor_lua_widget.SetSayCursor(false)   
        else
            quest.allow_game_cursor = false 
        end
        
        quest.do_not_change_curosor = false
        
    end
    if avatart_say == true then
        --avatar_widget.avatar_say = false
        avatar_widget.SetAvatarSay(false)
    end
    
end

local say_dialog_table = 
{
    left_top = {x = -1, y= -1, wtw = false, angle = 3.1415/2*3,
    get_arrow_offset = function (_dialog_size)
        return sf.misc.FloatVector(_dialog_size.X + quest.const_say_arrow_offset.Y, _dialog_size.Y - quest.const_say_arrow_offset.X)
    end,
    get_dialog_offset = function (_dialog_size, _arrow_size)
        return sf.misc.FloatVector( -_dialog_size.X - _arrow_size.Y - quest.const_say_arrow_offset.Y, - _dialog_size.Y  + quest.const_say_arrow_offset.X)
    end,

},

    right_bottom = {x = 1, y= 1, wtw = false, angle = 3.1415/2,
    get_arrow_offset = function (_dialog_size)
        return sf.misc.FloatVector(-quest.const_say_arrow_offset.Y, quest.const_say_arrow_offset.X)
    end,
    get_dialog_offset = function (_dialog_size, _arrow_size)
        return sf.misc.FloatVector(_arrow_size.Y + quest.const_say_arrow_offset.Y, - quest.const_say_arrow_offset.X)
    end,

},
    left_bottom = {x = -1, y= 1, wtw = true, angle = 3.1415,
    get_arrow_offset = function (_dialog_size)
        return sf.misc.FloatVector(_dialog_size.X - quest.const_say_arrow_offset.X, -quest.const_say_arrow_offset.Y)
    end,
    get_dialog_offset = function (_dialog_size, _arrow_size)
        return sf.misc.FloatVector(- (_dialog_size.X - quest.const_say_arrow_offset.X), _arrow_size.Y + quest.const_say_arrow_offset.Y)
    end,

},
    right_top = {x = 1, y= -1, wtw = true, angle = 0,
    get_arrow_offset = function (_dialog_size)
        return sf.misc.FloatVector(quest.const_say_arrow_offset.X, _dialog_size.Y + quest.const_say_arrow_offset.Y)
    end,
    get_dialog_offset = function (_dialog_size, _arrow_size)
        return sf.misc.FloatVector( - quest.const_say_arrow_offset.X, - _arrow_size.Y - quest.const_say_arrow_offset.Y - _dialog_size.Y)
    end,

},

}


function say_widget.form_say_widget(_widget, _say_text, _object, _offsetx, _offsety)

	local x_offset, y_offset = nil, nil
    if _offsety == nil and _offsetx and _object then
        _offsety = _offsetx
        _offsetx = _object
        x_offset, y_offset = 0, 0
    elseif _object then 
		local object = quest.FindRootObjectById(_object)
		__assert(object, "Объект '".._object.."' не найден!")
        local object_pos = quest.get_object_pos(_object)
        
        if not object_pos then
            __message("Объект на который указывает say не виден на сцене", "Ошибка")
            return nil
        end

		x_offset, y_offset = object_pos.X, object_pos.Y
	end

    if _offsetx then x_offset = x_offset + _offsetx end
    if _offsety then y_offset = y_offset + _offsety end

    local text = _say_text
    if type(text) == "number" then
        text = sf.misc.g_StringTable.Instance().FormatByStringsID("$"..tostring(_say_text))
    end

    local current_widget = _widget.GetWidgets()
    while not current_widget.IsEnd() do
        current_widget.Get().SetOffset(0, 0)
        current_widget.Next()
    end

    local text_widget = __cast(_widget.GetWidget("proto_say_text_widget", true), sf.gui.CLabelWidget)            
    __assert(text_widget, "В окне 'say_window' отсутствует label_widget 'proto_say_text_widget'!")
    text_widget.SetSize(400, 1)
    text_widget.SetText(text)
    
    local image_widget = __cast(_widget.GetWidget("background_image_widget", true), sf.gui.CImageWidget)            
    image_widget.GetImage().SetFlags(sf.misc.BitwiseOr(image_widget.GetImage().GetFlags(), sf.graphics.CImage.FlagBoxImage))

    image_widget.SetSize(1, 1)
    _widget.UpdateLayout()
    

    local dialog_size = _widget.GetSize()
    image_widget.SetSize(dialog_size.X, dialog_size.Y)

            
    local arrow_widget = __cast(_widget.GetWidget("bubblehelp_arrow_widget", true), sf.gui.CImageWidget)
    local arrow_size = arrow_widget.GetSize()
    
    local width_arrow_offset = arrow_size.X - quest.const_say_arrow_offset.X
    local height_arrow_offset = arrow_size.Y - quest.const_say_arrow_offset.Y

    local x, y = quest.const_say_arrow_face_offset.X, 768 - quest.const_say_arrow_face_offset.Y

    if x_offset then x = x_offset end
    if y_offset then y = y_offset end

    local nice_direction = nil
    for i,o in pairs(say_dialog_table) do
        local width = dialog_size.X
        local height = dialog_size.Y
        if o.wtw == true then
            width = (width + width_arrow_offset)*o.x + x
            height = (height + height_arrow_offset)*o.y + y
        else
            width = (width + height_arrow_offset)*o.x + x
            height = (height + width_arrow_offset)*o.y + y
        end
        if width < 0 or height < 0 or width > 1024 or height > 768 then
            
        else
            nice_direction = o
            break
        end
        
    end

    if nice_direction == nil then
        nice_direction = say_dialog_table["right_top"]
    end

    local arrow_offset = nice_direction.get_arrow_offset(dialog_size) 
    arrow_widget.SetRotation(sf.misc.MatrixRotation(nice_direction.angle))
    arrow_widget.SetOffset(arrow_offset.X, arrow_offset.Y)

    
    local dialog_offset = nice_direction.get_dialog_offset(dialog_size, arrow_size)
    _widget.SetOffset(x + dialog_offset.X, y + dialog_offset.Y)
    _widget.AddWidget(arrow_widget)    
    
    _widget.SetSize(1024, 768)

    local current_widget = _widget.GetWidgets()
    while not current_widget.IsEnd() do
        local offset = current_widget.Get().GetAbsPos(true)
        current_widget.Get().SetOffset(offset.X, offset.Y)
        current_widget.Next()
    end
    image_widget.GetSize()
    image_widget.GetOffset()

    _widget.SetOffset(0, 0)

    return {size = image_widget.GetSize(), offset = image_widget.GetOffset()}
end

function say_widget.show_tutorial(_say_text, _object, _offsetx, _offsety)

    if say_widget.form_say_widget(quest.tutorial_lua_widget, _say_text, _object, _offsetx, _offsety) ~= nil then
        tutorial_widget.Show(true)
    end
end

function say_widget.hide_tutorial()
    tutorial_widget.Show(false)
end


function say_widget.close_say(_value)
    if _value == nil then
        _value = 0
    end
    quest.global_say_window_result = _value
end


say_widget.say_table = {}

say_widget.common_say_table = {}

function say_widget.init_common_table()
    say_widget.common_say_table = {}
    say_widget.load_deafult_says()
    for i,o in ipairs(say_widget.say_table) do
        if o.item == nil and o.object == nil then
            table.insert(say_widget.common_say_table, o)
        end
    end
end

function say_widget.LoadConstants(_constants)
    local say_info = _constants.GetChildRef("say", false)
    if say_info then
        local res = tonumber(say_info.GetValue("after_say_delay").c_str())
        if res ~= nil then say_widget.after_sound_delay = res end

        res = tonumber(say_info.GetValue("letters_koef").c_str())
        if res ~= nil then say_widget.letters_koef = res end

        res = say_info.GetValue("allow_letters_koef").c_str()
        if res ~= "" then 
            if res == "true" then
                say_widget.allow_koef_close = true
            end
        end

        res = say_info.GetValue("allow_sound_close").c_str()
        if res ~= "" then 
            if res == "true" then
                say_widget.allow_sound_close = true
            end
        end



    end
end


function say_widget.load_deafult_says()
   local say_item = quest.game_resources.GetChild(_T("Constants"), false).GetChild(_T("say"), false).GetChild(_T("incorrect_say_list"), false).GetFirstChildRef()
	while say_item do
	    table.insert(say_widget.common_say_table, {item = nil, object = nil, say = tonumber(say_item.GetValue("value").c_str()) } )
	    say_item = say_item.GetNextSiblingRef()
	end
end

function say_widget.add_say(_item, _object, _say)
    table.insert(say_widget.say_table, {item = _item, object = _object, say = _say})
end

function init_random_say(_table)
    local items_count = #_table
    if items_count > 0 then
        say(_table[random(1, items_count)].say,nil,nil,nil,true)
    end
end

function say_widget.init_say(_item, _object)

    local total_ec = {}
    local part_ec = {}
    for i,o in ipairs(say_widget.say_table) do
        if o.item == _item and o.object == _object then
            table.insert(total_ec, o)
        elseif (o.item == _item and o.object == nil) or (o.item == nil and o.object == _object) then
            table.insert(part_ec, o)
        end
    end
    if #total_ec > 0 then
        init_random_say(total_ec)
    elseif #part_ec > 0 then
        init_random_say(part_ec)
    else
        init_random_say(say_widget.common_say_table)
    end
end
function empty_script_function(self)
		pre_click_event()
		wrone_item_click()
		post_click_event()
end

function wrone_item_click()
    -- если флаг сохранения объекта в курсоре установлен
    -- то не ругаемся  на то что объект остался в курсоре
    if quest.do_not_change_cursor_flag or quest.global_modify_level_flag then
		return
	end
	local cursor_object = nil
    if quest.global_cursor.GetCursorObject() ~= nil then
       cursor_object = quest.global_cursor.GetCursorObject().GetId().c_str()
       ---add_incorect_click()
       say_widget.init_say(cursor_object, quest.global_current_script_object.GetId().c_str())
       
   end
end

function say_widget.safety_say(...)
    if not threads_managment.IsClikThread() then
        say_widget.say(...)
    end
end		
