/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sample.tswebclient.cassandra;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;


/**
 *
 * Class that represents an application (folder or real application). This
 * is the object used in the Java (JSF) is just a collection of properties
 * (the ones defined in Attributes enumerated) and the children applications.
 *
 * @see CassandraManagerEJB
 * @author ricky
 */
public class Application implements Serializable {

    /**
     * Type of the application (folder or real application).
     */
    public enum Type {
        /**
         * Folder application can have children but no rdp.
         */
        FOLDER,

        /**
         * Real application. It cannot have any children and the rdp file
         * must be defined.
         */
        APPLICATION,
    };

    /**
     * The key or path od the application ("/APPLICATIONS/SKYPE" for example).
     */
    private String key = null;

    /**
     * The name of the application ("Skype" for example).
     */
    private String name = null;

    /**
     * The type of the application (application or folder).
     */
    private Type type = null;

    /**
     * png file mapped as a byte array.
     */
    private byte[] icon = null;

    /**
     * Custom description of the application.
     */
    private String description = null;

    /**
     * not used.
     */
    private String path = null;

    /**
     * rdp file content to launch terminal service with this application.
     */
    private byte[] rdp = null;

    /**
     * Array of children applications (in case of folder).
     */
    private List<Application> children = null;

    //
    // CONSTRUCTORS
    //

    /**
     * Protected constructor (only used in EJB) to construct a new application
     * only with the key or path.
     *
     * @param key The key or path of the application.
     */
    protected Application(String key) {
        this.key = key;
        children = new ArrayList<Application>();
    }

    /**
     * Another protected constructor used by the EJB. The new application is
     * constructed via key, name and type.
     *
     * @param key The application key or path.
     * @param name The application name.
     * @param type The application type.
     */
    protected Application(String key, String name, Type type) {
        this.key = key;
        this.name = name;
        this.type = type;
        children = new ArrayList<Application>();
    }

    /**
     * Public constructor using a parent application.
     *
     * @param parent The parent folder for the application.
     * @param name The application name.
     * @param type The application type.
     */
    public Application(Application parent, String name, Type type) {
        if (parent.equals(root())) {
            this.key = new StringBuilder("/").append(name.toUpperCase()).toString();
        } else {
            this.key = new StringBuilder(parent.key).append("/").append(name.toUpperCase()).toString();
        }
        this.name = name;
        this.type = type;
        children = new ArrayList<Application>();
    }

    /**
     * Public full constructor.
     *
     * @param parent The parent folder for the application.
     * @param name The application name.
     * @param type The application type.
     * @param icon The application icon.
     * @param description The application description.
     * @param path The application path.
     * @param rdp The application rdp file.
     */
    public Application(Application parent, String name, Type type,
            byte[] icon, String description, String path, byte[] rdp) {
        this(parent, name, type);
        this.description = description;
        this.icon = icon;
        this.path = path;
        this.rdp = rdp;
    }

    //
    // STATIC METHDODS
    //

    /**
     * Static method to retrieve the root folder parent. The "/" application
     * folder is a special application that can be obtained with this method.
     *
     * @return The application root folder "/".
     */
    static public Application root() {
        return new Application("/", "ROOT", Type.FOLDER);
    }

    //
    // GETTEERS & SETTERS
    //

    /**
     * Return application key or path.
     * @return key
     */
    public String getKey() {
        return key;
    }

    /**
     * Get application name.
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * Set application name.
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Check if the application is of type FOLDER.
     * @return true if folder.
     */
    public boolean isFolferType() {
        return Type.FOLDER.equals(type);
    }

    /**
     * Return the application type.
     * @return type
     */
    public Type getType() {
        return type;
    }

    /**
     * Set the application type.
     * @param type
     */
    public void setType(Type type) {
        this.type = type;
    }

    /**
     * Return the application description.
     * @return description
     */
    public String getDescription() {
        return description;
    }

    /**
     * Set the application description.
     * @param description
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * Return the application path.
     * @return path
     */
    public String getPath() {
        return path;
    }

    /**
     * Set the application path.
     * @param path
     */
    public void setPath(String path) {
        this.path = path;
    }

    /**
     * Return the application icon.
     * @return icon
     */
    public byte[] getIcon() {
        return icon;
    }

    /**
     * Set the application icon.
     * @param icon
     */
    public void setIcon(byte[] icon) {
        this.icon = icon;
    }

    /**
     * Return the application rdp file.
     * @return rdp
     */
    public byte[] getRdp() {
        return rdp;
    }

    /**
     * Set the application rdp file.
     * @param rdp
     */
    public void setRdp(byte[] rdp) {
        this.rdp = rdp;
    }

    /**
     * Method that return the list of application which are children of
     * this application (only folders can have children).
     *
     * @return The list of children applications (never null).
     */
    public List<Application> getChildren() {
        return children;
    }

    //
    // COMMON METHODS
    //

    /**
     * Method that return the key of the parent of this application.
     *
     * @return The application key of the parent.
     */
    public String getParentKey() {
        return Application.getParentKey(key);
    }

    /**
     * Static method that gets the application name of the parent. Parent key
     * is the same key but without the last application name ("/APPLICATIONS/SKYPE"
     * returns "/APLLICATIONS" and "/APPLICATIONS" returns "/", the root folder).
     *
     * @param key The key to obtain the name.
     * @return the parent key for the specified key.
     */
    static protected String getParentKey(String key) {
        int idx = key.lastIndexOf("/");
        if (idx == 0) {
            return "/";
        } else {
            return key.substring(0, idx);
        }
    }

    /**
     * Method that performs equals based on applycation key.
     *
     * @param o The object to compare.
     * @return true of false.
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof Application) {
            Application app = (Application) o;
            return this.key.equals(app.key);
        } else {
            return false;
        }
    }

    /**
     * The hashcode is performed on the key.
     * @return hashcode for this application.
     */
    @Override
    public int hashCode() {
        return key.hashCode();
    }

    /**
     * Methos to print the folder structure.
     * @param depth level of depth.
     * @param sb The builder to append.
     * @return The sb passed.
     */
    private StringBuilder printPath(int depth, StringBuilder sb) {
        for (int i = 0; i < depth*2; i++) {
            sb.append(" ");
        }
        sb.append("|-> ");
        sb.append(key);
        sb.append(" (");
        sb.append(name);
        sb.append(" | ");
        sb.append(type);
        sb.append(")");
        sb.append(System.getProperty("line.separator"));
        for (Application child: children) {
            child.printPath(depth+1, sb);
        }
        return sb;
    }

    /**
     * Method that prints the path (folder structure) for the application.
     * @return The string representation for this application structure.
     */
    public String printPath() {
        StringBuilder sb = new StringBuilder();
        return printPath(0, sb).toString();
    }

    /**
     * String representation of an application.
     * @return String representation.
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("*** ");
        sb.append(this.getClass().toString());
        sb.append(System.getProperty("line.separator"));
        sb.append("key: ");
        sb.append(key);
        sb.append(System.getProperty("line.separator"));
        sb.append("name: ");
        sb.append(name);
        sb.append(System.getProperty("line.separator"));
        sb.append("type: ");
        sb.append(type);
        sb.append(System.getProperty("line.separator"));
        sb.append("description: ");
        sb.append(description);
        sb.append(System.getProperty("line.separator"));
        sb.append("icon: ");
        sb.append(icon);
        sb.append(System.getProperty("line.separator"));
        sb.append("rdp: ");
        sb.append(rdp);
        sb.append(System.getProperty("line.separator"));
        sb.append("path: ");
        sb.append(path);
        for (Application child: children) {
            sb.append(System.getProperty("line.separator"));
            sb.append(" |-> ");
            sb.append(child.key);
            sb.append(" (");
            sb.append(child.name);
            sb.append(")");
        }
        sb.append(System.getProperty("line.separator"));
        return sb.toString();
    }
}

