/*
 * Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.fhcrc.cpl.viewer.commandline.modules;

import org.fhcrc.cpl.toolbox.ApplicationContext;
import org.fhcrc.cpl.toolbox.commandline.arguments.*;
import org.fhcrc.cpl.toolbox.filehandler.TabLoader;
import org.fhcrc.cpl.toolbox.commandline.CommandLineModuleExecutionException;
import org.fhcrc.cpl.toolbox.commandline.CommandLineModule;
import org.apache.log4j.Logger;


import java.io.*;
import java.util.*;


/**
 * Command linemodule for plotting the mass calibration of a feature file
 */
public class CollapseSpreadsheetRowsCLM extends BaseViewerCommandLineModuleImpl
        implements CommandLineModule
{
    protected static Logger _log = Logger.getLogger(CollapseSpreadsheetRowsCLM.class);

    protected String collapseColumnName = null;
    protected File inFile;
    protected File outFile;
    protected String separatorString = ";";
    protected List<String> otherColsToCollapse = new ArrayList<String>();


    public CollapseSpreadsheetRowsCLM()
    {
        init();
    }

    protected void init()
    {
        mCommandName = "collapsespreadsheetrows";
        mShortDescription = "collapse multiple rows in a spreadsheet with the same value for collapsecolumn";
        CommandLineArgumentDefinition[] argDefs =
                {
                        createUnnamedFileArgumentDefinition(true,"input spreadsheet"),
                        new StringArgumentDefinition("collapsecolumn", true, "column to split on"),
                        new FileToWriteArgumentDefinition("out", false, "output file"),
                        new StringArgumentDefinition("separator", false,
                                "String to split on", separatorString),
                        new StringListArgumentDefinition("othercolstocollapse", false,
                                "other columns to collapse (rather than keep one value). Any column NOT on this list " +
                                        "must have only one unique value, or an error is thrown."),
                };
        addArgumentDefinitions(argDefs);
    }

    public void assignArgumentValues()
            throws ArgumentValidationException
    {
        inFile = getUnnamedFileArgumentValue();
        collapseColumnName = getStringArgumentValue("collapsecolumn");
        separatorString = getStringArgumentValue("separator");
        outFile = getFileArgumentValue("out");
        otherColsToCollapse = getStringListArgumentValue("othercolstocollapse");

        if (otherColsToCollapse != null && !otherColsToCollapse.isEmpty()) {
            ApplicationContext.infoMessage("collapsing other columns:");
            for (String col : otherColsToCollapse)
                ApplicationContext.infoMessage("\t" + col);
        }
    }
    
    /**
     * do the actual work
     */
    public void execute() throws CommandLineModuleExecutionException
    {
        PrintWriter outPW = null;
        try
        {
            outPW = new PrintWriter(outFile);

            TabLoader loader = new TabLoader(inFile);
            List<TabLoader.ColumnDescriptor> columns =
                    new ArrayList<TabLoader.ColumnDescriptor>();
            StringBuffer headerLine = new StringBuffer();
            boolean firstColumn = true;
            for (TabLoader.ColumnDescriptor column : loader.getColumns())
            {
                columns.add(column);
                if (firstColumn)
                    firstColumn = false;
                else
                    headerLine.append("\t");
                headerLine.append(column.name);
            }
            outPW.println(headerLine.toString());
            outPW.flush();

            Map<String, List<Map>> keyRowsMap = new HashMap<String, List<Map>>();

            Map[] rowsAsMaps = (Map[])loader.load();

            int lineNum = 0;
            for (Map row : rowsAsMaps)
            {
                lineNum++;
                Object collapseVal = row.get(collapseColumnName);
                if (collapseVal == null) {
                    throw new CommandLineModuleExecutionException("Null collapse value for line " + lineNum);
                }
                String key = collapseVal.toString();

                List<Map> rows = keyRowsMap.get(key);
                if (rows == null) {
                    rows = new ArrayList<Map>();
                    keyRowsMap.put(key, rows);
                }
                rows.add(row);
            }

            for (String key : keyRowsMap.keySet()) {
                StringBuffer lineBuf = new StringBuffer();
                List<Map> rows = keyRowsMap.get(key);
                boolean firstCol = true;
                for (TabLoader.ColumnDescriptor column : loader.getColumns()) {
                    String valString = "";

                    if (key.equals(collapseColumnName))
                        valString = key;
                    else {
                        List<String> allValsThisCol = new ArrayList<String>();
                        for (Map row : rows) {
                            String val = "";
                            if (row.containsKey(column.name) && row.get(column.name) != null)
                                val = row.get(column.name).toString();
                            allValsThisCol.add(val);
                        }

                        if (otherColsToCollapse.contains(column.name)) {
                            boolean firstVal = true;
                            for (String val : allValsThisCol) {
                                if (!firstVal)
                                    valString = valString + separatorString;
                                valString = valString + val;
                                firstVal = false;
                            }
                        }
                        else {
                            Set<String> uniqueVals = new HashSet<String> (allValsThisCol);
                            if (uniqueVals.size() > 1 && uniqueVals.contains("")) {
                                uniqueVals.remove("");
                            }
                            if (uniqueVals.size() > 1)       {
                                ApplicationContext.infoMessage("Vals:");
                                for (String val : uniqueVals)
                                    ApplicationContext.infoMessage("\t" + val);
                                throw new CommandLineModuleExecutionException("Key " + key + ", col " + column.name +
                                        ", vals: " + uniqueVals.size());
                            }
                            valString = uniqueVals.iterator().next();
                        }
                    }

                    lineBuf.append(firstCol ? "" : "\t");
                    lineBuf.append(valString);

                    firstCol = false;
                }
                outPW.println(lineBuf.toString());
                outPW.flush();

            }


        }
        catch (Exception e)
        {
            throw new CommandLineModuleExecutionException(e);
        }
        finally
        {
            if (outPW != null)
                outPW.close();
        }
    }

}

@@ -6745,32 +6745,390 @@
 () %3E 1)       %7B%0A
+                                boolean firstVal = true;%0A                                for (String val : uniqueVals) %7B%0A                                    if (!firstVal)%0A                                        valString = valString + separatorString;%0A                                        valString = valString + val;%0A                                %7D%0A//
                 
@@ -7180,24 +7180,26 @@
 e(%22Vals:%22);%0A
+//
             
@@ -7248,16 +7248,18 @@
 ueVals)%0A
+//
         
@@ -7326,24 +7326,26 @@
 %5Ct%22 + val);%0A
+//
             
@@ -7450,16 +7450,18 @@
 .name +%0A
+//
         
@@ -7547,32 +7547,71 @@
               %7D%0A
+                            else %7B%0A    
                 
@@ -7660,24 +7660,54 @@
 r().next();%0A
+                            %7D%0A
             

change to CollapseSpreadsheetRows