/* 
 *	Copyright (C) 2003-2006 Gabest
 *	http://www.gabest.org
 *
 *  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 2, 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 GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#pragma once

#include "StringMap.h"
#include "Glyph.h"

namespace ssf
{
	template<class T>
	class Cache
	{
	protected:
		StringMapW<T> m_key2obj;
		CAtlList<CStringW> m_objs;
		size_t m_limit;

	public:
		Cache(size_t limit) {m_limit = max(1, limit);}
		virtual ~Cache() {RemoveAll();}

		void RemoveAll()
		{
			POSITION pos = m_key2obj.GetStartPosition();
			while(pos) delete m_key2obj.GetNextValue(pos);
			m_key2obj.RemoveAll();
			m_objs.RemoveAll();
		}

		void Add(const CStringW& key, T& obj, bool fFlush = true)
		{
			if(StringMapW<T>::CPair* p = m_key2obj.Lookup(key)) delete p->m_value;
			else m_objs.AddTail(key);

			m_key2obj[key] = obj;

			if(fFlush) Flush();
		}

		void Flush()
		{
			while(m_objs.GetCount() > m_limit)
			{
				CStringW key = m_objs.RemoveHead();
				ASSERT(m_key2obj.Lookup(key));
				delete m_key2obj[key];
				m_key2obj.RemoveKey(key);
			}
		}

		bool Lookup(const CStringW& key, T& val)
		{
			return m_key2obj.Lookup(key, val) && val;
		}

		void Invalidate(const CStringW& key)
		{
			T val;
			if(m_key2obj.Lookup(key, val))
			{
				delete val;
				m_key2obj[key] = NULL;
			}
		}
	};

	class FontCache : public Cache<FontWrapper*> 
	{
	public:
		FontCache() : Cache(20) {}
		FontWrapper* Create(HDC hDC, const LOGFONT& lf);
	};

	class GlyphPathCache : public Cache<GlyphPath*>
	{
	public:
		GlyphPathCache() : Cache(100) {}
		GlyphPath* Create(HDC hDC, const FontWrapper* f, WCHAR c);
	};

	class Row : public CAutoPtrList<Glyph>
	{
	public:
		int ascent, descent, border, width;
		Row() {ascent = descent = border = width = 0;}
	};

	class RenderedSubtitle
	{
	public:
		CRect m_spdrc;
		CRect m_clip;
		CAutoPtrList<Glyph> m_glyphs;

		RenderedSubtitle(const CRect& spdrc, const CRect& clip) : m_spdrc(spdrc), m_clip(clip) {}
		virtual ~RenderedSubtitle() {}

		CRect Draw(SubPicDesc& spd) const;
	};

	class RenderedSubtitleCache : public Cache<RenderedSubtitle*>
	{
	public:
		RenderedSubtitleCache() : Cache(10) {}
	};

	class SubRect
	{
	public:
		CRect rect;
		float layer;
		SubRect() {}
		SubRect(const CRect& r, float l) : rect(r), layer(l) {}
	};

	class SubRectAllocator : public StringMapW<SubRect>
	{
		CSize vs;
		CRect vr;
	public:
		void UpdateTarget(const CSize& vs, const CRect& vr);
		void GetRect(CRect& rect, const Subtitle* s, const Align& align, int tlb, int brb);
	};

	class Renderer
	{
		HDC m_hDC;

		FontCache m_fc;
		GlyphPathCache m_gpc;
		RenderedSubtitleCache m_rsc;
		SubRectAllocator m_sra;

	public:
		Renderer();
		virtual ~Renderer();

		void NextSegment(const CAutoPtrList<Subtitle>& subs);
		RenderedSubtitle* Lookup(const Subtitle* s, const CSize& vs, const CRect& vr);
	};
}