/** @mainpage Dekoratorius
 *
 * Pirmoji u�duotis objektini� technologij� kursui.
 *
 * Autorius: Marius Gedminas (mgedmin@@gedmin.as)
 *
 * VU MIF, informatika, 1M kursas, 1 grup�.
 *
 * 2002 m. ruduo.
 *
 * @section problem Problema
 *
 * Projektuokime dokument� tvarkymo sistem�.  Dokumentai gali b�ti �vairi�
 * r��i� (tekstas, paveiksliukai ir t.t.).  Dokumentus galime per�i�rin�ti,
 * spausdinti, redaguoti.
 *
 * Taip pat norime keisti ar papildyti kai kuri� konkre�i� dokument� elges�.
 * Pavyzd�iui, u�drausti kai kuri� dokument� redagavim�, ar prikabinti prie
 * dokument� anotacijas.
 *
 * Jei kiekvienam variantui kursime po atskir� klas�, gausime kombinatorin�
 * sprogim� -- %TextDocument, ReadOnlyTextDocument, AnnotatedTextDocument,
 * AnnotatedReadOnlyTextDocument ir t.t.
 *
 * @section solution Sprendimas
 *
 * Pritaikysime Dekoratoriaus �ablon�.  Kiekvien� dokumento tip� atitinka
 * atskira klas�.  Visi dokumentai paveldi i� bendros astrak�ios bazin�s klas�s
 * ir realizuoja t� pat� interfeis�, nusakant� bazin� dokument� funkcionalum�.
 *
 * Papildomas savybes suteiks dekoratoriai.  Abstrakti dekoratoriaus klas�
 * paveldi i� bazin�s dokument� klas�s ir realizuoja bendr� visiems
 * dekoratoriams funkcionalum� -- metod� delegavim�.
 *
 * Tradiciniame Dekoratoriaus �ablono variante dokumentai nieko ne�ino apie
 * dekoratorius, ne�ino net apie j� egzistavim�.  Ta�iau tokiu atveju galime
 * lengvai nuimti tik i�orin� dekoratori�, jei �inome jo tip�.  Taip pat galime
 * lengvai pasinaudoti tik i�orinio dekoratoriaus (jei �inome jo tip�)
 * pateikiamomis papildomomis funkcijomis, nes dekoratoriai deleguoja tik
 * dokument� interfeiso funkcijas.  Nor�t�si ko nors lankstesnio.
 *
 * Tur�dami kok� nors objekt� (ne�inodami, ar jis dekoruotas, ar ne), mes
 * nor�tum�me su�inoti (gauti nuorod�) � tam tikros konkre�ios klas�s
 * dekoratori� (kad gal�tum�me pasinaudoti jo teikiamomis papildomomis
 * funkcijomis).  Taip pat nor�tum�me i�mesti i� dekoratori� grandin�s vien�
 * ar visus nurodyto tipo dekoratorius.
 *
 * Kad pasiektum�me papildomai i�keltus tikslus turime kiek pakeisti tradicin�
 * Dekoratoriaus �ablon� ir prid�ti kelias funkcijas � dokument� bazin� klas�
 * (negalime j� prid�ti � dekoratori� bazin� klas�, nes norime ir nedekoruotus
 * objektus traktuoti vienodai).
 *
 * @section implementation Realizacija
 *
 * @image html classdiagram.png "Klasi� diagrama"
 * @image latex classdiagram.eps "Klasi� diagrama" width=12cm
 *
 * Klases galima sugrupuoti � tokias kategorijas:
 * - @ref interfaces "Interfeisai" (@ref Document, @ref Decorator)
 * - @ref documents  "Konkret�s dokumentai" (@ref TextDocument, @ref Image)
 * - @ref decorators "Konkret�s dekoratoriai" (@ref ReadOnly, @ref Annotation)
 *
 * Pagrindin�je programoje pateiktas @ref example "naudojimo pavyzdys".
 */

#include "decorator.h"

#include <iostream>

// Document

Document::~Document()
{}

// Decorator

Decorator::~Decorator()
{
    delete next_;
}

// TextDocument

void TextDocument::view()
{
    std::cout << "tekstinio dokumento per�i�ra\n";
}

void TextDocument::print()
{
    std::cout << "tekstinio dokumento spausdinimas\n";
}

void TextDocument::edit()
{
    std::cout << "tekstinio dokumento redagavimas\n";
}

// Image

void Image::view()
{
    std::cout << "paveiksliuko per�i�ra\n";
}

void Image::print()
{
    std::cout << "paveiksliuko spausdinimas\n";
}

void Image::edit()
{
    std::cout << "paveiksliuko redagavimas\n";
}

// ReadOnly

void ReadOnly::edit()
{
    std::cout << "negalima redaguoti �io dokumento!\n";
}

// Annotation
void Annotation::view()
{
    Decorator::view();
    std::cout << "  anotacija: " << annotation() << '\n';
}

void Annotation::print()
{
    Decorator::print();
    std::cout << "  anotacija: " << annotation() << '\n';
}

/**
 * @addtogroup example Pavyzdys
 * @{
 */

/**
 * Pagrindin� programa, iliustruojanti dekoratori� panaudojim�.  J� �vykd�ius
 * tur�t� pasirodyti �itoks tekstas:
@verbatim

  * Bazinis funkcionalumas
  tekstinio dokumento per�i�ra
  tekstinio dokumento spausdinimas
  tekstinio dokumento redagavimas
  paveiksliuko per�i�ra
  paveiksliuko spausdinimas
  paveiksliuko redagavimas

  * Bazinis funkcionalumas su dekoratoriais
  tekstinio dokumento per�i�ra
    anotacija: �domus dokumentas
  tekstinio dokumento spausdinimas
    anotacija: �domus dokumentas
  negalima redaguoti �io dokumento!
  paveiksliuko per�i�ra
    anotacija: gra�us paveiksliukas
    anotacija: o man nepatiko
  paveiksliuko spausdinimas
    anotacija: gra�us paveiksliukas
    anotacija: o man nepatiko
  paveiksliuko redagavimas

  * Papildomas funkcionalumas: pakeiskime anotacij�
  tekstinio dokumento per�i�ra
    anotacija: o gal ir nelabai �domus

  * Pereikime per visus vieno tipo dekoratorius
  radau anotacij�: o man nepatiko
  radau anotacij�: gra�us paveiksliukas

  * Nuimkime ReadOnly dekoratori�
  tekstinio dokumento redagavimas

@endverbatim
 */
int main()
{
    // Sukuriame plikus objektus
    Document* txt = new TextDocument();
    Document* img = new Image();

    // Bazinis funkcionalumas
    cout << "* Bazinis funkcionalumas\n";
    txt->view();
    txt->print();
    txt->edit();
    img->view();
    img->print();
    img->edit();
    cout << '\n';

    // Prikabiname dekoratorius
    txt = new Annotation(txt, "�domus dokumentas");
    txt = new ReadOnly(txt);

    img = new Annotation(img, "gra�us paveiksliukas");
    img = new Annotation(img, "o man nepatiko");

    // Bazinis funkcionalumas su dekoratoriais
    cout << "* Bazinis funkcionalumas su dekoratoriais\n";
    txt->view();
    txt->print();
    txt->edit();
    img->view();
    img->print();
    img->edit();
    cout << '\n';

    // Papildomas funkcionalumas
    cout << "* Papildomas funkcionalumas: pakeiskime anotacij�\n";
    if (Annotation* a = txt->decorator<Annotation>()) {
	a->changeAnnotation("o gal ir nelabai �domus");
	txt->view();
    };
    cout << '\n';

    // Parodykime visas anotacijas
    cout << "* Pereikime per visus vieno tipo dekoratorius\n";
    for (Document* tmp = img;
         Annotation* d = tmp->decorator<Annotation>();
         tmp = d->next())
    {
	std::cout << "radau anotacij�: " << d->annotation() << '\n';
    }
    cout << '\n';

    // Nuimkime dekoratori�
    cout << "* Nuimkime ReadOnly dekoratori�\n";
    txt = txt->unwrap<ReadOnly>(true);
    txt->edit();
    cout << '\n';

    // Panaikinkime objektus ir visus dekoratorius
    delete txt;
    delete img;
}

/// @}


syntax highlighted by Code2HTML, v. 0.9.1