/*
 * @BEGIN LICENSE
 *
 * Psi4: an open-source quantum chemistry software package
 *
 * Copyright (c) 2007-2017 The Psi4 Developers.
 *
 * The copyrights for code used from other parties are included in
 * the corresponding files.
 *
 * This file is part of Psi4.
 *
 * Psi4 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, version 3.
 *
 * Psi4 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 Psi4; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * @END LICENSE
 */

#ifndef _PSI_SRC_LIB_LIBDIIS_DIISENTRY_H_
#define _PSI_SRC_LIB_LIBDIIS_DIISENTRY_H_

#include <string>
#include <map>

namespace psi{

class PSIO;

  /**
   * @brief The DIISManager class is used to manage DIIS quantities and
   * their corresponding error vectors.
   */

class DIISEntry{
    public:
        /**
         * @brief The type of quantity to add to either an error vector or vector.
         *
         * DPDBuf4  - A pointer to a four-index DPD quantity, assumed to be initialized
         *            via dpd_buf4_init() already.
         * DPDFile2 - A pointer to a two-index DPD quality, assumed to be initialized
         *            via dpd_file2_init() already.
         * Matrix   - A pointer to a Psi Matrix object.
         * Vector   - A pointer to a Psi Vector object.
         * Pointer  - The quantity will be taken from contiguous memory pointed to by a
         *            double* pointer.  In this case, the next parameter passed to the
         *            set_size.. routines should be the number of elements to read.
         * Psio     - The PSIO object to use for I/O
         */
        enum InputType {DPDBuf4, DPDFile2, Matrix, Vector, Pointer};
        DIISEntry(std::string label, int ID, int count, int vectorSize, double *vector,
                  int errorVectorSize, double *errorVector, std::shared_ptr<PSIO> psio);
        ~DIISEntry();
        /// Whether the dot product of this entry's and the nth entry's error vector is known
        bool dot_is_known_with(int n) {return _knownDotProducts[n];}
        /// The dot product of this entry's and the nth entry's error vectors
        double dot_with(int n) {return _dotProducts[n];}
        /// The RMS error of this entry
        double rmsError() {return _rmsError;}
        /// The absolute number of this entry
        int orderAdded() {return _orderAdded;}
        /// Sets the dot product with vector n to val
        void set_dot_with(int n, double val) {_knownDotProducts[n] = true; _dotProducts[n] = val;}
        /// Marks the dot product with vector n as invalid
        void invalidate_dot(int n) {_knownDotProducts[n] = false;}
        /// Set the vector
        void set_vector(double *vec) {_vector = vec;}
        /// set the error vector
        void set_error_vector(double *vec) {_errorVector = vec;}
        /// Put this vector entry on disk and free the memory
        void dump_vector_to_disk();
        /// Allocate vector memory and read from disk
        void read_vector_from_disk();
        /// Put this error vector entry on disk and free the memory
        void dump_error_vector_to_disk();
        /// Allocate error vector memory and read from disk
        void read_error_vector_from_disk();
        /// Free vector memory
        void free_vector_memory();
        /// Free error vector memory
        void free_error_vector_memory();
        /// Returns the error vector
        const double *errorVector() {read_error_vector_from_disk(); return _errorVector;}
        /// Returns the vector
        const double *vector() {read_vector_from_disk(); return _vector;}
        /// Open the psi file, if needed.
        void open_psi_file();
        /// Close the psi file, if needed.
        void close_psi_file();
    protected:
        /// The list of which dot products, with other DIISEntries, are known
        std::map<int, bool> _knownDotProducts;
        /// The list of known dot products with other DIISEntries
        std::map<int, double> _dotProducts;
        /// The length of the error vector
        int _errorVectorSize;
        /// The length of the vector
        int _vectorSize;
        /// The absolute number of this entry
        int _orderAdded;
        /// The number of this entry in the current subspace
        int _ID;
        /// The RMS error for this entry
        double _rmsError;
        /// The error vector
        double *_errorVector;
        /// The error vector
        double *_vector;
        /// The label used for disk storage
        std::string _label;
        /// PSIO object
        std::shared_ptr<PSIO> _psio;
};

} // End namespace

#endif // Header guard
