/* Copyright (C) 2001-2007  Stephan Michels <stephan@vern.chem.tu-berlin.de>
 *
 * Contact: cdk-devel@lists.sf.net
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 * All we ask is that proper credit is given for our work, which includes
 * - but is not limited to - adding the above copyright notice to the beginning
 * of your source code files, and to any copyright notice that you may distribute
 * with programs based on this work.
 *
 * 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
package org.openscience.cdk.math.qm;

import org.openscience.cdk.math.Matrix;
import org.openscience.cdk.math.Vector;

/**
 * This class represents a set of orbitals
 *
 * @author Stephan Michels &lt;stephan@vern.chem.tu-berlin.de&gt;
 * @cdk.githash
 * @cdk.created 2001-06-14
 * @cdk.module  qm
 */
public class Orbitals {

    private int    count_basis;
    private int    count_orbitals;
    private Matrix C;
    private IBasis basis;
    private int    count_electrons = 1;

    /**
     * Constructs orbitals with a specified base set
     */
    public Orbitals(IBasis basis) {
        this.basis = basis;
        count_orbitals = count_basis = basis.getSize();
        C = new Matrix(count_basis, count_basis);
        for (int i = 0; i < count_basis; i++)
            for (int j = 0; j < count_basis; j++)
                if (i == j)
                    C.matrix[i][j] = 1d;
                else
                    C.matrix[i][j] = 0d;
    }

    /**
     * Constructs orbitals with a specified base set and a coefficient matrix
     */
    public Orbitals(IBasis basis, Matrix C) {
        this.basis = basis;
        count_basis = basis.getSize();
        if (count_basis == C.rows) {
            this.C = C;
            count_orbitals = C.columns;
        } else {
            this.C = new Matrix(count_basis, count_basis);
            for (int i = 0; i < count_basis; i++)
                for (int j = 0; j < count_basis; j++)
                    if (i == j)
                        this.C.matrix[i][j] = 1d;
                    else
                        this.C.matrix[i][j] = 0d;
            count_orbitals = count_basis;
        }
    }

    /**
     * Set a coefficient matrix
     */
    public void setCoefficients(Matrix C) {
        if (count_basis == C.rows) {
            this.C = C;
            count_orbitals = C.columns;
        }
    }

    /**
     * Get the coefficient matrix
     */
    public Matrix getCoefficients() {
        return C;
    }

    /**
     * Get the function value of a orbital at the position (x,y,z)
     */
    public double getValue(int index, double x, double y, double z) {
        double sum = 0;
        for (int i = 0; i < count_basis; i++)
            if (C.matrix[i][index] != 0d) sum += C.matrix[i][index] * basis.getValue(i, x, y, z);
        return sum;
    }

    /**
     * Get the function value of a orbital
     */
    public Vector getValues(int index, Matrix m) {
        if (m.rows != 3) return null;

        Vector result = basis.getValues(0, m).mul(C.matrix[0][index]);
        for (int i = 1; i < count_basis; i++)
            if (C.matrix[i][index] != 0d) result.add(basis.getValues(i, m).mul(C.matrix[0][index]));
        return result;
    }

    /**
     * Returns the basis set of this orbitals
     */
    public IBasis getBasis() {
        return basis;
    }

    /**
     * Set the count of bases
     */
    public int getCountBasis() {
        return count_basis;
    }

    /**
     * Returns the count of orbitals
     */
    public int getCountOrbitals() {
        return count_orbitals;
    }

    /**
     * Sets the count of electrons, which occupies the orbitals
     */
    public void setCountElectrons(int count) {
        if (count > 0) count_electrons = count;
    }

    /**
     * Gets the count of electrons, which occupies the orbitals
     */
    public int getCountElectrons() {
        return count_electrons;
    }
}
