///////////////////////////////////////////////////////////////////////////////
// For information as to what this class does, see the Javadoc, below.       //
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
// 2007, 2008, 2009, 2010, 2014, 2015 by Peter Spirtes, Richard Scheines, Joseph   //
// Ramsey, and Clark Glymour.                                                //
//                                                                           //
// This program is free software; you can redistribute it and/or modify      //
// it under the terms of the GNU General Public License as published by      //
// the Free Software Foundation; either version 2 of the License, or         //
// (at your option) any later version.                                       //
//                                                                           //
// This program is distributed in the hope that it will be useful,           //
// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
// GNU General Public License for more details.                              //
//                                                                           //
// You should have received a copy of the GNU General Public License         //
// along with this program; if not, write to the Free Software               //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
///////////////////////////////////////////////////////////////////////////////

package edu.cmu.tetrad.data;

import edu.cmu.tetrad.graph.Node;
import edu.cmu.tetrad.util.NamingProtocol;


/**
 * Base class for variable specifications for DataSet.  These objects govern the
 * types of values which may be recorded in a Column of data and provide
 * information about the interpretation of these values.  Variables of every
 * type must provide a marker which is recorded in a column of data for that
 * variable when the value is missing; this missing data marker should not be
 * used for other purposes.
 *
 * @author Willie Wheeler 7/99
 * @author Joseph Ramsey modifications 12/00
 */
public abstract class AbstractVariable implements Variable {
    static final long serialVersionUID = 23L;

    public static int LAST_ID = 0;

    /**
     * Name of this variable.
     *
     * @serial
     */
    private String name = "??";

    /**
     * Builds a variable having the specified name.
     */
    AbstractVariable(String name) {
        if (name == null) {
            throw new NullPointerException();
        }

        name = name.trim();

//        if (!NamingProtocol.isLegalName(name)) {
//            throw new NullPointerException(
//                    NamingProtocol.getProtocolDescription() + ": " + name);
//        }

        this.name = name;
    }

    /**
     * @return the missing value marker as an Object.
     */
    public abstract Object getMissingValueMarker();

    /**
     * Tests whether the given value is the missing data marker.
     */
    public abstract boolean isMissingValue(Object value);

    /**
     * Sets the name of this variable.
     */
    public final void setName(String name) {
        if (name == null) {
            throw new NullPointerException(
                    "AbstractVariable name must not be null.");
        }

        if (!NamingProtocol.isLegalName(name)) {
            throw new IllegalArgumentException(
                    NamingProtocol.getProtocolDescription());
        }

        this.name = name;
    }

    /**
     * @return the name of this variable.
     */
    public final String getName() {
        return name;
    }

    /**
     * Checks to see whether the passed value is an acceptable value for
     * <tt>this</tt> variable.  For <tt>AbstractVariable</tt>, this method
     * always returns <tt>true</tt>. </p> Subclasses should override
     * <tt>checkValue()</tt> in order to provide for subclass-specific value
     * checking.  The value should pass the test if it can be converted into
     * an equivalent object of the correct class type (see
     * <tt>getValueClass()</tt> for this variable; otherwise, it should fail. In
     * general, <tt>checkValue()</tt> should not fail a value for simply not
     * being an instance of a particular class. </p> Since this method is not
     * <tt>static</tt>, subclasses may (but need not) provide for
     * instance-specific value checking.
     *
     * @param value a value
     * @return <tt>true</tt> if the value is an acceptable value for
     * <tt>this</tt> variable, and <tt>false</tt> otherwise
     */
    public boolean checkValue(Object value) {
        return true;
    }

    /**
     * @return a String representation of this variable.  Specifically, the name
     * of the variable is returned.
     */
    public String toString() {
        return name;
    }

    public abstract Node like(String name);


    public int compareTo(Object o) {
        Node node = (Node) o;
        final String name = getName();

        // This splitting is too slow in an inner loop.
//        String[] tokens1 = name.split(":");
        final String _name = node.getName();
//        String[] tokens2 = _name.split(":");

        return name.compareTo(_name);

//        if (tokens1.length == 1) {
//            tokens1 = new String[]{tokens1[0], "0"};
//        }
//
//        if (tokens2.length == 1) {
//            tokens2 = new String[]{tokens2[0], "0"};
//        }
//
//        int i1 = tokens1[1].compareTo(tokens2[1]);
//        int i2 = tokens1[0].compareTo(tokens2[0]);
//
//        if (i1 == 0) {
//            return i2;
//        }
//        else {
//            return i1;
//        }
    }
}





