/** @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