/**
 * UGENE - Integrated Bioinformatics Tools.
 * Copyright (C) 2008-2023 UniPro <ugene@unipro.ru>
 * http://ugene.net
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#pragma once

#include <QMap>
#include <QVarLengthArray>

#include <U2Core/global.h>

namespace U2 {
// Type of Weight matrix
enum PWMatrixType {
    PWM_MONONUCLEOTIDE,
    PWM_DINUCLEOTIDE
};

class U2CORE_EXPORT UniprobeInfo {
public:
    // default empty constructor
    UniprobeInfo();

    // constructor from parsed data
    UniprobeInfo(const QMap<QString, QString>& properties);

    // constructor from raw data
    UniprobeInfo(const QString& data);

    QString getProperty(const QString& name) const;

    QMap<QString, QString> getProperties() const;

    bool operator==(const UniprobeInfo& i1) const {
        return i1.properties == properties;
    }

private:
    QMap<QString, QString> properties;
};

// Position frequency matrix
// Also known as PSSM - Position score-specific matrix
class U2CORE_EXPORT PWMatrix {
    friend class WMatrixSerializer;

public:
    // create empty matrix
    PWMatrix();

    // create matrix from pre-counted data
    PWMatrix(const QVarLengthArray<float>& matrix, const PWMatrixType& type);

    // get internal index of position in 1-dimensional array
    int index(int row, int column) const;

    // get length of matrix row
    int getLength() const;

    // get type of matrix: mono- or dinucleotide
    PWMatrixType getType() const;

    // get value at specified position
    float getValue(int row, int column) const;

    // get sum of minimum values in each column
    float getMinSum() const;

    // get sum of maximum values in each column
    float getMaxSum() const;

    // set UniPROBE info for matrix
    void setInfo(const UniprobeInfo& info);

    // get specified UniPROBE property
    QString getProperty(const QString& propertyName) const;

    // get all UniPROBE properties
    QMap<QString, QString> getProperties() const;

    bool operator==(const PWMatrix& m1) const {
        // FIXME: for some reasons QT == operator didn't work for gcc compiler
        if (m1.data.size() != data.size())
            return false;
        for (int i = 0; i < m1.data.size(); i++) {
            if (m1.data.at(i) != data.at(i))
                return false;
        }
        return m1.length == length &&
               m1.type == type &&
               m1.minSum == minSum &&
               m1.maxSum == maxSum &&
               m1.info == info;
    };

private:
    QVarLengthArray<float> data;
    int length;
    PWMatrixType type;
    float minSum;
    float maxSum;
    UniprobeInfo info;
};

}  // namespace U2
