class 'Subtitles'
-------------------------------------------------------------

function Subtitles:__init(parent, timer)
    self.stack          = {}
    self.fields         = {}
    self.fade_time      = 0.5;
    
    self.parent         = parent
    self.timer          = timer
    
    self.modes           = {}
    self.modes.NONE      = 0
    self.modes.PLAYABLE  = 1
    self.modes.CLACKABLE = 2
    self.mode            = self.modes.NONE
    
    self.font_name      = COMICS_FONT
    self.text_width     = 910
	self.text_height    = 80
    self.text_scale     = 0.7
    self.text_spacing   = 0.8
	self.text_tracking  = 0
	self.text_alignment = HGETEXT_CENTER + HGETEXT_MIDDLE
	self.text_x         = 512
	self.text_y         = 710
	self.text_z         = 250
end
-------------------------------------------------------------

function Subtitles:pushReplic(text, start_time, end_time)
    if start_time == nil or end_time == nil then
        self.mode = self.modes.CLICKABLE
    end
    
    local info = {}
    info.effector = nil
    info.tf       = nil
    info.shown    = false
    info.hided    = false
    
    info.text     = text
    info.time     = start_time
    info.dt       = (self.mode ~= self.modes.CLICKABLE) and (end_time - start_time)
                                                         or nil
    
    table.insert(self.stack, info)
    
    return info
end
-------------------------------------------------------------

function Subtitles:pushVoicedReplic(sound, text, start_time, end_time)
    local info = Subtitles.pushReplic(self, text, start_time, end_time)
    
    if type(sound) == 'string' then
        local soundName = ExtractFileName(sound)
        LoadSound(soundName, sound)
        info.sound = MakeSoundEntity(soundName)
    else
        info.sound = sound
    end
end
-------------------------------------------------------------

function Subtitles:play()
    assert(self.mode == self.modes.NONE)
    local max_time = 0
    
    for i, info in ipairs(self.stack) do
        max_time = math.max(max_time, info.time + info.dt)
        
        self.timer:Add( function()
                            local tf = self:_getTextField()
                            tf:SetText(GetString(info.text))
                            tf:SetVisible(true)
                            
                            local fade_time = math.min(self.fade_time, info.dt)
                            
                            local eff = CreateAnimationEffector()
                            eff:SetDestroysOnEnd(true)
                            eff:AttachTo(tf)
                            eff:SetKey(_TRACK_O, 0,                        0)
                            eff:SetKey(_TRACK_O, fade_time,                1)
                            eff:SetKey(_TRACK_O, info.dt,                  1)
                            eff:SetKey(_TRACK_O, info.dt + self.fade_time, 0)
                            eff:Play()
                            
                            self.fields[tf] = false
                            info.effector   = eff
                            info.tf         = tf
                            info.shown      = true
                            
                            if info.sound then
                                info.sound:PlaySound(false)
                            end
                            
                            self.timer:Add( function()
                                                self.fields[tf] = true
                                                info.effector   = nil
                                                info.tf         = nil
                                                info.hided      = true
                                                
                                                tf:SetVisible(false)
                                            end,
                                            info.dt + self.fade_time)
                        end,
                        info.time)
    end
    
    if max_time ~= 0 and self.on_finish ~= nil then
        self.timer:Add( self.on_finish, max_time + self.fade_time)
    end
end
-------------------------------------------------------------

function Subtitles:showNextReplic()
    assert(self.mode == self.modes.CLICKABLE)
    
    local shown_index = #self.stack + 1
    
    for i=1, #self.stack do
        local info = self.stack[i]
        
        if not info.shown then
            local tf = self:_getTextField()
            tf:SetText(GetString(info.text))
            tf:SetVisible(true)
        
            local eff = CreateAnimationEffector()
            eff:SetDestroysOnEnd(true)
            eff:AttachTo(tf)
            eff:SetKey(_TRACK_O, 0,              0)
            eff:SetKey(_TRACK_O, self.fade_time, 1)
            eff:Play()
        
            self.fields[tf] = false
            info.effector   = eff
            info.tf         = tf
            info.shown      = true
            
            if info.sound then
                info.sound:PlaySound(false)
            end
        
            self.timer:Add( function()
                            info.effector = nil
                        end,
                        self.fade_time)
            
            shown_index = i
            break
        end
    end
    
    if shown_index > 1 and not self.stack[shown_index-1].hided then
        local prev_info = self.stack[shown_index-1]
        
        if prev_info.effector then
            prev_info.effector:Destroy()
        end
        
        local eff = CreateAnimationEffector()
        eff:SetDestroysOnEnd(true)
        eff:AttachTo(prev_info.tf)
        eff:SetKey(_TRACK_O, 0,              1)
        eff:SetKey(_TRACK_O, self.fade_time, 0)
        eff:Play()
        
        prev_info.effector = eff
        prev_info.hided    = true
        
        if prev_info.sound then
            prev_info.sound:StopSound()
        end
        
        self.timer:Add( function()
                        self.fields[prev_info.tf] = true
                        prev_info.effector = nil
                        prev_info.tf       = nil
                        
                        if shown_index == #self.stack + 1 and self.on_finish ~= nil then
                            self.on_finish()
                        end
                    end,
                    self.fade_time)
    end
end
-------------------------------------------------------------

function Subtitles:stop()
	self.timer:Clear()
	
	for i, info in ipairs(self.stack) do
        if info.sound then
            info.sound:StopSound()
        end
    end
	
	for tf, _ in pairs(self.fields) do
		self.fields[tf] = true
		tf:SetVisible(false)
	end
end
-------------------------------------------------------------

function Subtitles:_createTextField()
    local field = CreateTextEntity(self.font_name, "")
    field:SetTextAlignment(self.text_alignment)
    field:SetBorderSize(self.text_width, self.text_height)
    field:SetXY(self.text_x, self.text_y)
    field:SetZ(self.text_z)
    field:SetScale(self.text_scale)
    field:SetSpacing(self.text_spacing)
    field:SetTracking(self.text_tracking)
    field:AttachTo(self.parent)
    field:SetVisible(false)
        
    self.fields[field] = true
    
    return field;
end
-------------------------------------------------------------

function Subtitles:_getTextField()
    local tf = nil
                            
    for _tf, _free in pairs(self.fields) do
        if _free then
            tf = _tf
            break
        end
    end

    if tf == nil then
        tf = self:_createTextField()
    end
    
    return tf
end
-------------------------------------------------------------