//Kolokwium ZPR, 2020.11.17 - sa tutaj 2 polecenia ogolne (linia 3 i linia 8)

//1. Prosze umiescic swoje imie i nazwisko

const char* IMIE = "ROBERT";
const char* NAZWISKO = "NOWAK";

//2. Prosze oznaczyc linie, ktore zostaly zmodyfikowane dodajac krotki komentarz

#include <string>
#include <stack>
#include <vector>
#include <list>
#include <iostream>
#include <iomanip>
#include <memory>
#include <cassert>

using namespace std;

// ZAD1, 4 pkt
//
// Ponizej przedstawiona lista dwukierunkowa przechowuje liczby calokowite.
// Oprócz standardowych wskaźników na element poprzedni i następny, element listy ma uchwyt na element następny po następnym.
// Obserwujemy nieprawidlowe zwalnianie obiektow, przyklad - kod funkcji zad1().
// Popraw kod.

class List {

    struct Element;
    using PElement = shared_ptr<Element>;
    using PWElement = weak_ptr<Element>;

    struct Element {
        Element(int v) : val_(v) { cout << "c-tor " << val_ << endl; }
        ~Element() { cout << "d-tor " << val_ << endl; }
        int val_;
        PElement next_;
        PWElement prev_;  //slaby sprytny wskaznik
        PWElement next2_; //slaby sprytny wskaznik
    };
public:
    List() {}
    ~List() { }
    void push_front(int v) {
        PElement e = make_shared<Element>(v);
        if(head_ ) {
            e->next_ = head_;
            head_->prev_ = e;
            e->next2_ = head_->next_;
        }
        head_ = e;
    }
private:
    PElement head_;
};

void zad1() {
    List l;
    for(int i=0; i< 10; ++i)
        l.push_front(i);
}

//ZAD2, 6 pkt
//
// Błędy związane z obsługą plików są reprezentowane przez klasy FileError, dla tej hierarchii jest dostępny wzorzec wizytatora.
// Obsługa błędów polega na wyświetleniu komunikatu, tak jak pokazano w pliku 'zad2'.
// Zmodyfikuj tą funkcję, aby obsługa błędu nie wymagała wielokrotnych instrukcji 'catch', które są kosztowne.

class Visitor;

class FileError : public std::exception {
public:
    FileError(const string& name) : filename_(name) {}
    virtual void accept(Visitor& v)  = 0;
    const string& getName() const { return filename_; }
private:
    string filename_;
};

class FileReadError;
class FileWriteError;
class FileCreateError;
class FileRemoveError;

class Visitor {
public:
    virtual ~Visitor() {}
    virtual void visit(FileReadError&) = 0;
    virtual void visit(FileWriteError&) = 0;
    virtual void visit(FileCreateError&) = 0;
    virtual void visit(FileRemoveError&) = 0;
};

class FileReadError : public FileError {
public:
    FileReadError(const string& name) : FileError(name) {}
    virtual void accept(Visitor& v) { v.visit(*this); }
};

class FileWriteError : public FileError {
public:
    FileWriteError(const string& name) : FileError(name) {}
  virtual void accept(Visitor& v) { v.visit(*this); }
};

class FileCreateError : public FileError {
public:
    FileCreateError(const string& name) : FileError(name) {}
  virtual void accept(Visitor& v) { v.visit(*this); }
};

class FileRemoveError : public FileError {
public:
    FileRemoveError(const string& name) : FileError(name) {}
  virtual void accept(Visitor& v) { v.visit(*this); }
};

class MsgGenerator : public Visitor {
public:
    virtual void visit(FileReadError& e) { msg_ = "Error of reading file " + e.getName(); }
    virtual void visit(FileWriteError& e) { msg_ = "Error of writing file " + e.getName(); }
    virtual void visit(FileCreateError& e) { msg_ = "Can not create file " + e.getName(); }
    virtual void visit(FileRemoveError& e) { msg_ = "File " + e.getName() + "can not be removed"; }
    string msg_;
};


void zad2() {
  try {
    throw FileWriteError("test.txt");
    //kod ktory moze zglosic wyjatek z hierarchii Exception
  // } catch(FileReadError& e) {
  //     cerr << "Error of reading file " << e.getName() << endl;
  // } catch(FileWriteError& e) {
  //      cerr << "Error of writing file " << e.getName() << endl;
  // } catch(FileCreateError& e) {
  //     cerr << "Can not create file " << e.getName() << endl;
  // } catch(FileRemoveError& e) {
  //      cerr << "File " << e.getName() << "can not be removed" << endl;
  // }
  } catch(FileError& e) {
      MsgGenerator gen;
      e.accept(gen);
      cerr << gen.msg_ << endl;
  }
}


// ZAD3 3 pkt
// Usuń niektóre składniki sumy w ostatniej linii funkcji 'zad3', aby wydrukować liczbę liter Twojego imienia, które wpisałeś do stałej IMIE w 5 linii tego pliku

class B1 {
public:
    virtual int f() { return 0; }
    int g() { return 0; }
};

class B2 : public B1 {
public:
    virtual int f() { return 1; }
    int g() { return 1; }
};

class B3 : public B2 {
public:
    virtual int f() { return 2; }
    int g() { return 2; }
};

class B4 : public B3 {
public:
    virtual int f() { return 4; }
    int g() { return 4; }
};

void zad3() {
    B4 obj;
    B4* b4 = &obj;
    B3* b3 = &obj;
    B2* b2 = &obj;
    B1* b1 = &obj;

    int x1 = b4->f();
    int x2 = b4->g();
    int x3 = b3->f();
    int x4 = b3->g();
    int x5 = b2->f();
    int x6 = b2->g();
    int x7 = b1->f();
    int x8 = b1->g();


    //cout << x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 << endl;
    cout << x1 + x4 << endl;
}


// ZAD4 5 pkt
// Uzupełnij metody w klasie Book.
// operator przypisania, operator przypisania przenoszący, destruktor
// Test w funkcji zad4()

class Image { //reprezentuje okladke
public:
    Image(const string&) { cout << "c-tor image" << endl; }
    Image(const Image&) { cout << "cc-tor image" << endl; }
    ~Image() { cout << "d-tor image" << endl; }
};

class Book {
public:
    Book(const string& name) : name_(name), image_(new Image(name) ) {  }
    Book(const Book& book) : name_(book.name_), image_(new Image(*image_)) {    }
    Book(Book&& book) : name_(book.name_), image_(std::move(book.image_)) { }

    Book& operator=(const Book& book) {
        name_ = book.name_;
        image_.reset(new Image(*book.image_));
        return *this;
    }
    Book& operator=(Book&& book) {
        name_ = book.name_;
        image_ = std::move(book.image_);
        return *this;
    }
    ~Book() {
    }
private:
    string name_;
    unique_ptr<Image> image_;
};

Book f(Book b) {
    return b;
}

void zad4() {
    Book b1("a");
    Book b2 = b1;
    Book b3 = f(b1);
    b2 = b1;
    b3 = f(b1);
}


// ZAD5 7 pkt
//
// Ponizej pokazano fragment kodu gry w warcaby.
// Obiekt typu 'State' reprezentuje stan w grze, tzn. polozenie pionow, damek oraz informacja o tym, kto sie rusza.
// Dostarczamy trzech roznych wersji gry: warcaby włoskie, warcaby niemieckie i warcaby hiszpanskie.
// Wszystkie takie wersje uzywaja planszy 8x8, ale roznia sie mozliwoscia bicia pionem do tyłu oraz możliwością ruchu damki o wiele pól.
// Te modyfikacje wplywaja na implementacje metod 'nextMovementsXXX'.
// Dostarczamy takze trzy algorytmy dla gracza: algorytm losowy - wybiera jeden z dostepnych ruchow losowo, algorytm AI - wybiera jeden z dostepnych ruchow
// wykorzystujac algorytmy przeszukiwania drzewa gry oraz algorytm 'Human', ktory o propozycje ruchu pyta gracza.

// (1) Uprosc strukture klas, aby nie powielac kodu.
// (2) Jakiego obiektowego wzorca projektowego uzyles?


/** reprezentuje stan w grze w warcaby (polozenie pionow i informacja o tym, kto sie rusza */
struct State {};
using States = vector<State>;

// class Player {
//  virtual State nextMove(State s) = 0;
// };

// class ItalianAIPlayer : public Player {
// public:
//  ItalianAIPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };

// class GermanAIPlayer : public Player {
// public:
//  GermanAIPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };

// class SpanishAIPlayer : public Player {
// public:
//  SpanishAIPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };


// class ItalianRandomPlayer : public Player {
// public:
//  ItalianRandomPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };

// class GermanRandomPlayer : public Player {
// public:
//  GermanRandomPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };

// class SpanishRandomPlayer : public Player {
// public:
//  SpanishRandomPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };


// class ItalianHumanPlayer : public Player {
// public:
//  ItalianHumanPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };

// class GermanHumanPlayer : public Player {
// public:
//  GermanHumanPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };

// class SpanishHumanPlayer : public Player {
// public:
//  SpanishHumanPlayer();
//  State nextMove(State s);
// private:
//  States nextMovementsItalian(State s);
// };

//Rozwiazanie: wzorzec mostu

class Checkers { //klasa bazowa implementacji - rozne rodzaje warcabow
public:
   virtual States nextMovements(State s) = 0;
};

class ItalianCheckers : public Checkers {
    virtual States nextMovements(State s);
};

class GermanCheckers : public Checkers {
    virtual States nextMovements(State s);
};

class SpanishCheckers : public Checkers {
    virtual States nextMovements(State s);
};

class Player {
public:
    Player(Checkers& ch) : checkers_(ch) {}

    virtual State nextMove(State s) = 0;
protected:
    virtual States nextMovements(State s) {
        return checkers_.nextMovements(s);
    }
private:
    Checkers& checkers_;
};

class RandomPlayer : public Player {
public:
    RandomPlayer(Checkers& ch) : Player(ch) {}
    State nextMove();
};

class AIPlayer : public Player {
public:
    AIPlayer(Checkers& ch) : Player(ch) {}
    State nextMove();
};

class HumanPlayer : public Player {
public:
    HumanPlayer(Checkers& ch) : Player(ch) {}
    State nextMove();
};

int main() {
    cout << "Kolokwium ZPR, rozwiazania " << IMIE << " " << NAZWISKO << endl;
    cout << "zad1"<<endl;
    zad1();
    cout << "zad2"<<endl;
    zad2();
    cout << "zad3"<<endl;
    zad3();
    cout << "zad4"<<endl;
    zad4();
    //  cout << "zad5"<<endl;
    //  zad5();
    cout << endl;
    return 0;
}
