Index: trunk/FACT++/src/fitsdump.cc
===================================================================
--- trunk/FACT++/src/fitsdump.cc	(revision 12726)
+++ trunk/FACT++/src/fitsdump.cc	(revision 12727)
@@ -59,4 +59,5 @@
     fits* fFile;
     bool fDotsPlease;
+    bool fNoZeroPlease;
     string fFilename;
 
@@ -99,4 +100,5 @@
     int doCurvesDisplay( const vector<string> &list, const string& tableName);
 #endif
+    int doMinMaxPlease(const string& filename, const vector<string>& list, int precision);
     int doStatsPlease(const string &filename, const vector<string>& list, int precision);
     //    bool Plot(const vector<string> &list);
@@ -113,5 +115,5 @@
 //!        the ostream where to redirect the outputs
 //
-FitsDumper::FitsDumper() : fFile(0), fDotsPlease(false)
+FitsDumper::FitsDumper() : fFile(0), fDotsPlease(false), fNoZeroPlease(false)
 {
 }
@@ -453,5 +455,5 @@
             return -1;
     }
-
+#ifdef PLOTTING_PLEASE
     if (conf.Get<bool>("stat") && conf.Get<bool>("graph"))
     {
@@ -459,5 +461,26 @@
         return -1;
     }
-
+#endif
+    if (conf.Get<bool>("minmax") && conf.Get<bool>("stat"))
+    {
+        cout << "Invalid combination of options: cannot do stats and minmax. Aborting" << endl;
+        return -1;
+    }
+#ifdef PLOTTING_PLEASE
+    if (conf.Get<bool>("minmax") && conf.Get<bool>("graph"))
+    {
+        cout << "Invalid combination of options: cannot graph minmax. Aborting" << endl;
+        return -1;
+    }
+#endif
+    if (conf.Get<bool>("stat") && conf.Get<bool>("nozero"))
+    {
+        cout << "Invalid combination of options: nozero only works with minmax. Aborting" << endl;
+        return -1;
+    }
+    if (conf.Get<bool>("nozero"))
+    {
+        fNoZeroPlease = true;
+    }
     if (conf.Get<bool>("list"))
         List();
@@ -467,4 +490,15 @@
         if (!OpenTable(conf.Get<string>("tablename")))
             return -1;
+    }
+
+    if (conf.Get<bool>("minmax"))
+    {
+        if (!conf.Has("col"))
+        {
+            cout << "Please specify the columns that should be dumped as arguments. Aborting" << endl;
+            return 0;
+        }
+        doMinMaxPlease(conf.Get<string>("outfile"), conf.Get<vector<string>>("col"), conf.Get<int>("precision"));
+        return 0;
     }
 
@@ -532,4 +566,125 @@
 {
     // 
+}
+
+struct minMaxStruct {
+    double min;
+    double max;
+    double average;
+    long numValues;
+    minMaxStruct() : min(1e10), max(-1e10), average(0), numValues(0) {}
+};
+
+int FitsDumper::doMinMaxPlease(const string& filename, const vector<string>& list, int precision)
+{
+
+    //first of all, let's separate the columns from their ranges and check that the requested columns are indeed part of the file
+    vector<pair<int, int> > ranges;
+    vector<string> listNamesOnly;
+
+    if (!separateColumnsFromRanges(list, ranges, listNamesOnly))
+    {
+        cerr << "Something went wrong while extracting the columns names from parameters. Aborting" << endl;
+        return false;
+    }
+
+    ofstream out(filename=="-"?"/dev/stdout":filename);
+    if (!out)
+    {
+        cerr << "Cannot open file " << filename << ": " << strerror(errno) << endl;
+        return false;
+    }
+
+    out.precision(precision);
+
+    // Loop over all columns in our list of requested columns
+    vector<pair<char, char*> > columnsData;
+    vector<minMaxStruct> statData;
+    int numRows = fFile->GetInt("NAXIS2");
+    auto rangesIt = ranges.begin();
+    for (vector<string>::const_iterator it=listNamesOnly.begin(); it!=listNamesOnly.end(); it++, rangesIt++)
+    {
+        fits::Table::Column& cCol = fColMap.find(*it)->second;
+        columnsData.push_back(make_pair(cCol.type, new char[cCol.num*cCol.size]));
+//        minMaxStuct initData;
+        statData.push_back(minMaxStruct());
+        fFile->SetPtrAddress(*it, columnsData[columnsData.size()-1].second);
+    }
+
+    int row = 0;
+    while (fFile->GetNextRow() && row < numRows)
+    {
+        rangesIt = ranges.begin();
+        auto statsIt = statData.begin();
+        for (auto it=columnsData.begin(); it != columnsData.end(); it++, rangesIt++, statsIt++)
+        {
+            double cValue = 0;
+            for (int i=rangesIt->first; i<rangesIt->second; i++)
+            {
+            switch (it->first) {
+                case 'L':
+                        cValue = reinterpret_cast<bool*>(it->second)[i];
+                        break;
+                case 'B':
+                        cValue = reinterpret_cast<bool*>(it->second)[i];
+                        break;
+                case 'I':
+                        cValue = reinterpret_cast<int16_t*>(it->second)[i];
+                        break;
+                case 'J':
+                        cValue = reinterpret_cast<int32_t*>(it->second)[i];
+                        break;
+                case 'K':
+                        cValue = reinterpret_cast<int64_t*>(it->second)[i];
+                        break;
+                case 'E':
+                        cValue = reinterpret_cast<float*>(it->second)[i];
+                        break;
+                case 'D':
+                        cValue = reinterpret_cast<double*>(it->second)[i];
+                        break;
+                default:
+                    ;
+            }
+            if (!fNoZeroPlease || cValue != 0)
+            {
+                statsIt->average += cValue;
+                if (cValue < statsIt->min)
+                    statsIt->min = cValue;
+                if (cValue > statsIt->max)
+                    statsIt->max = cValue;
+                statsIt->numValues++;
+            }
+            }
+        }
+        row++;
+    }
+    for (auto it = columnsData.begin(); it != columnsData.end(); it++)
+        delete[] it->second;
+
+    //okay. So now I've got ALL the data, loaded.
+    //let's do the summing and averaging in a safe way (i.e. avoid overflow of variables as much as possible)
+    rangesIt = ranges.begin();
+    auto statsIt = statData.begin();
+
+    auto nameIt = listNamesOnly.begin();
+    for (auto it=columnsData.begin(); it != columnsData.end(); it++, rangesIt++, statsIt++, nameIt++)
+    {
+        int span = rangesIt->second - rangesIt->first;
+        cout << *nameIt << ": " << endl;
+        if (statsIt->numValues != 0)
+        {
+            statsIt->average /= statsIt->numValues;
+            out << "min: " << statsIt->min << endl;
+            out << "max: " << statsIt->max << endl;
+            out << "mea: " << statsIt->average << endl;
+        }
+        else
+        {
+            out << "min: 0" << endl << "max: 0" << endl << "mea: " << endl;
+        }
+
+    }
+    return true;
 }
 
@@ -549,5 +704,5 @@
     out << "Max: " << reinterpret_cast<T*>(array)[numElems-1] << endl;
     if (numElems%2 == 0)
-        out << "Med: " << (reinterpret_cast<T*>(array)[numElems/2] + reinterpret_cast<T*>(array)[numElems/2+1])/2.f << endl;
+        out << "Med: " << (reinterpret_cast<T*>(array)[numElems/2] + reinterpret_cast<int16_t*>(array)[numElems/2+1])/2.f << endl;
     else
         out << "Med: " << reinterpret_cast<T*>(array)[numElems/2+1] << endl;
@@ -957,4 +1112,6 @@
         ("header,h",    po_switch(),                "Dump header of given table")
         ("stat,s",      po_switch(),                "Perform statistics instead of dump")
+        ("minmax,m",    po_switch(),                "Calculates min and max of data")
+        ("nozero,z",    po_switch(),                "skip 0 values for stats")
 #ifdef PLOTTING_PLEASE
         ("graph,g",     po_switch(),                "Plot the columns instead of dumping them")
