//    Copyright 2011 Brad Block, Pawjaw, LLC. (brad@pawjaw.com)
//
//    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 3 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, see <http://www.gnu.org/licenses/>.

package com.pawjaw.linalg;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class MatrixBuilder {
    private int rows, columns;
    private long offset;
    public Map<Long, Double> value_idxpair = new HashMap();

    public MatrixBuilder(int rows, int columns) {
        offset = (this.rows = rows) > (this.columns = columns) ? rows : columns;
    }

    public void set(int row, int column, double value) {
        if(value != 0)
            value_idxpair.put((long)row + (long)column * offset, value);
        else
            value_idxpair.remove((long)row + (long)column * offset);
    }

    public void add(int row, int column, double increment) {
        long idxpair = (long)row + (long)column * offset;
        Double value = value_idxpair.get(idxpair);
        if(value == null)
            value_idxpair.put(idxpair, increment);
        else if((value += increment) != 0)
            value_idxpair.put(idxpair, value);
        else
            value_idxpair.remove(idxpair);
    }

    public Matrix toMatrix(Matrix m) {
        int i = 0, j = 0, p = 0, vals = value_idxpair.size(), row, column;
        long[] idxpairs = new long[vals];
        m.rows = rows;
        m.cols = columns;
        m.vals = vals;
        m.pointr = new int[columns + 1];
        m.rowind = new int[vals];
        m.value = new double[vals];
        for(Long idxpair : value_idxpair.keySet())
            idxpairs[i++] = idxpair;
        Arrays.sort(idxpairs);
        for(long idxpair : idxpairs) {
            row = (int)(idxpair % offset);
            column = (int)(idxpair / offset);
            while(j < column)
                m.pointr[++j] = p;
            m.rowind[p] = row;
            m.value[p] = value_idxpair.get(idxpair);
            p++;
        }
        m.pointr[j+1] = p;
        return m;
    }

    public Matrix toMatrix() {
        return toMatrix(new Matrix());
    }

    public String toSummary() {
        StringBuilder sb = new StringBuilder();
        sb.append(rows);
        sb.append(" rows, ");
        sb.append(columns);
        sb.append(" columns, ");
        sb.append(value_idxpair.size());
        sb.append(" values");
        return sb.toString();
    }
}
