package vut.msa.helpers;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import vut.msa.pojos.BackupDisk;
import vut.msa.pojos.Client;
import vut.msa.pojos.ClientInformation;

/**
 * Helper pre objekt Client. Trieda poskytuje zakladne funkcie pre pracu s objektom
 * Client (klient), ako su vytvorenie, zmazanie, ziskanie a podobne.
 * 
 */
public class ClientHelper extends Helper {

    private Client client;
    private static final Logger llog = Logger.getLogger(UsersHelper.class);

    public ClientHelper() {
        super();
        client = new Client();
    }

    /**
     * Metoda vrati objekt Client, ktory je aktualne ulozeny v triede.
     *
     * @return objekt Client
     */
    public Client getClient() { return this.client; }

    /**
     * Metoda vrati klienta podla zadaneho ID.
     *
     * @param id ID hladaneho klienta
     * @return klient so zadanym ID
     */
    public Client getClient(int id) {

        try {
            openSession();
            Query q =
                    session.createQuery("from Client c where"
                    + " c.id=" + id);
            client = (Client) q.uniqueResult();
            if (client != null)
                session.load(Client.class, client.getId());
            else
                return null;
        } catch (Exception ex) {
            endTransaction(session.getTransaction(), false);
            llog.error("Nie je mozne ziskat klienta z databazy.", ex);
        } finally {
        }

        return client;
    }

    /**
     * Metoda vrati klienta z databazy na zaklade zadaneho nazvu klienta.
     *
     * @param name nazov klienta
     * @return klient z databazy
     */
    public Client getClientByName(String name) {
        try {
            openSession();
            Query q =
                    session.createQuery("from Client c where"
                    + " c.clientName='" + name + "'");
            client = (Client) q.uniqueResult();
            if (client != null)
                session.load(Client.class, client.getId());
            else
                return null;
        } catch (Exception ex) {
            endTransaction(session.getTransaction(), false);
            llog.error("Nie je mozne ziskat klienta z databazy.", ex);
        } finally {
        }

        return client;
    }

    /**
     * Metoda sluzi na autorizaciu klienta. Metoda overuje ci sa v databaze
     * nachadza zadane ID a heslo.
     *
     * @param clientId ID klienta
     * @param password autorizacne heslo klienta
     * @return autorizovany klient
     */
    public Client authorizeClient( String clientId, String password) {

        llog.info("Autorizujem klienta: " + clientId);

        try {
            openSession();
            //TODO: Ukladat a overovat heslo v DB ako hash!
            String encrypted  =
                    vut.msa.security.MessageHash.getInstance().encrypt(password);
            Query q =
                    session.createQuery("from Client c where"
                    + " c.password='" + password
                    + "' and c.clientId='" + clientId + "'");
            client = (Client) q.uniqueResult();
            if (client != null)
                session.load(Client.class, client.getId());
            else
                return null;
        } catch (Exception ex) {
            endTransaction(session.getTransaction(), false);
            llog.error("Nie je mozne autorizovat klienta.", ex);
        } finally {
        }

        return client;
    }

    /**
     * Metoda vrati zoznam vsetkych klientov, ktory sa nachadzaju v databaze.
     *
     * @return zoznam klientov, objekt List
     */
    public List<Client> getClientsList() {

        List<Client> clients = new ArrayList();

        try {
            openSession();
            Query q =
                    session.createQuery("from Client order by clientName");

            clients = q.list();

            for (Client u : clients) {               
                session.load(Client.class, u.getId());
            }

        } catch (Exception ex) {
            endTransaction(session.getTransaction(), false);
            log.error("Nie je mozne ziskat zoznam klientov z databazy.", ex);
        }

        return clients;
    }

    /**
     * Metoda vrati zoznam klientov, ktory sa ukladaju na zadany disk.
     *
     * @return zoznam klientov, objekt List
     */
    public List<Client> getClientsList(String diskName) {

        List<Client> clients = new ArrayList();

        try {
            openSession();
            Query q =
                    session.createQuery("from Client c where c.backupDisk ='"
                     + diskName + "'");

            clients = q.list();

            for (Client u : clients) {
                session.load(Client.class, u.getId());
            }

        } catch (Exception ex) {
            endTransaction(session.getTransaction(), false);
            log.error("Nie je mozne ziskat zoznam klientov z databazy.", ex);
        }

        return clients;
    }

    /**
     * Metoda ulozi noveho klienta do databazy.
     * 
     * @param client novy klient
     * @return true, ak sa operacia podarila; false, ak operacia zlyhala
     */
    public boolean addClient(Client client) {

        try {
            openSession();

            //Jedna sa o transietny objekt, preto treba volat persist
            session.persist(client);

            endTransaction(session.getTransaction(), true);

            openSession();

            ClientInformation info = new ClientInformation(client);
            session.persist(info);
            client.setInformation(info);
            session.saveOrUpdate(client);

            endTransaction(session.getTransaction(), true);
            return true;

        } catch (Exception lex) {
            llog.error(lex.getMessage());
            return false;
        }
    }

    /**
     * Metoda sluzi na aktualizaciu datumu poslednej zalohy klienta v tabulke
     * klientov po uspesnom nahrani zalohy na server.
     *
     * @param c klient, ktory ma byt aktualizovany
     */
    public void uploadSucces(Client c) {

        try {
            openSession();
            log.info("Aktualizujem..." + c.getId());

            c = (Client) session.load(Client.class, c.getId());
            c.setLastUpdate(new Date());
            session.saveOrUpdate(c);

            log.info("Relacia: " + session);
            endTransaction(session.getTransaction(), true);
            
        } catch (Exception ex) {
            endTransaction(session.getTransaction(), false);
            llog.error("Nie je mozne aktualizovat klienta.", ex);
        } finally {
        }
    }

    /**
     * Metoda zmaze klienta z databazy.
     *
     * @param userToRemove klient, ktory ma byt zmazany
     * @return true, ak sa operacia podari; false, ak sa nepodari
     */
    public boolean removeClient(Client userToRemove) {
        try {
            openSession();

            client = (Client) session.get(Client.class, userToRemove.getId());
            ClientInformation info = client.getInformation();

            if (info != null) {
                log.info("Mazem klienta a info: " + info.getId());
                session.delete(info);
            }
            
            session.delete(client);
            
            endTransaction(session.getTransaction(), true);
            return true;
            
        } catch (Exception lex) {
            lex.printStackTrace();
            llog.error(lex.getMessage());
            return false;
        }
    }

    /**
     * Metoda zmeni zalohovaci disk klientov. Tato funkcia sa vola pri prekopirovani
     * zaloh na iny disk.
     *
     * @param oldDiskName nazov stareho disku
     * @param newDiskName nazov noveho disku
     */
    public void changeBackupDiskForClients (String oldDiskName, String newDiskName) {

        List<Client> list = getClientsList(oldDiskName.replace("\\", "\\\\"));
        Iterator<Client> iterator = list.iterator();

        openSession();
        while (iterator.hasNext()) {
            Client c = iterator.next();

            c.setBackupDisk(new BackupDisk(newDiskName));
            session.update(c);
        }
        endTransaction(session.getTransaction(), true);
    }

}
