"""
     Copyright (C) 2007-2009 Franco Lanza <nextime@nexlab.it>
     Copyright (C) 2007-2009 Sandro Aliano <ita595@hotmail.com>
     Copyright (C) 2007-2009 Ivan Bellia <skylive@skylive.it>


     Web site: http://www.astronomix.org/trac/Skylive-NG

     This file is part of Skylive-NG.

     Skylive-NG 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.

     Skylive-NG 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 Skylive-NG.  If not, see <http://www.gnu.org/licenses/>.
"""

"""
   zscale_levels and percentile_levels are directly derived ( if not entirely
   copied ) from zscale_rande and percentile_range functions contained in the file 
   fitsimage.py from the wcs2kml project from google code.

   Original URL for wcs2kml is http://code.google.com/p/wcs2kml.

   For those two function declaration the original copyright, as reported
   above, is applied.

   Thanks to the Jeremy Brewer, original author of those functions.

 Copyright (c) 2005, 2006, 2007, Jeremy Brewer

 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
 met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the
      distribution.
    * The names of the contributors may not be used to endorse or
      promote products derived from this software without specific prior
      written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""


import pointarray
import numpy

def zscale_levels(scidata, contrast=0.25, npoints=600, nrows=120):
   """
      Zscale algorithm from Iraf to determine strmin and strmax 
      level values

      scidata -> is a numpy.ndarray data type and shuld be an image,
      contrast -> contrast level for zscale
      npoints -> number of points of the sampled data
      nrows -> number of points per row of the sampled data

      Zscale work by using a sample of the total data for performance.

   """

   if len(scidata.shape) != 2:
      raise ValueError("scidata isn't an image!")
   
   if contrast <= 0:
      contrast = 1

   if npoints > scidata.size or npoints <= 0:
      npoints = int(scidata.size/2)

   ncols = int(float(npoints)/float(nrows)+0.5)
   xsize, ysize = scidata.shape
   rskip = float(xsize-1)/float(nrows-1)
   cskip = float(ysize-1)/float(ncols-1)

   data=[]
   for i in xrange(nrows):
      x = int(i*rskip+0.5)
      for a in xrange(ncols):
         y = int(a*cskip+0.5)
         data.append(scidata[x, y])

   npixs = len(data)
   data.sort()
   dmin=min(data)
   dmax=max(data)
   cpixs=int((npixs+1)/2)
   if dmin == dmax:
      return dmin, dmax
   if npixs % 2 == 0:
      med = data[cpixs-1]
   else:
      med = 0.5*(data[cpixs-1]+data[cpixs])

   pixind=map(float, xrange(npixs))
   points=pointarray.PointArray(pixind, data, min_err=1.0e-4)
   fit=points.sigmaIterate()

   nallowed=0
   for pt in points.allowedPoints():
      nallowed += 1

   if nallowed < int(int(npixs)/2):
      return dmin, dmax

   z1 = med-(cpixs-1)*(fit.slope/contrast)
   z2 = med+(npixs-cpixs)*(fit.slope/contrast)

   zmin=dmin
   if z1  > dmin:
      zmin = z1
   zmax=dmax
   if z2 < dmax:
      zmax = z2

   if zmin >= zmax:
      return dmin, dmax

   return zmin, zmax

def percentile_levels(image_data, min_percent=3.0, max_percent=99.0,
                num_points=5000, num_per_row=250):

   """
   Computes the range of pixel values to use when adjusting the contrast
   of FITs images using a simple percentile cut.  For efficiency reasons,
   only a subsample of the input image data is used.

   Input:  image_data  -- the array of data contained in the FITs image
                     (must have 2 dimensions)
         min_percent -- min percent value between (0, 100)
         max_percent -- max percent value between (0, 100)
         num_points  -- the number of points to use when sampling the
                     image data
         num_per_row -- number of points per row when sampling
   """
   if not 0 <= min_percent <= 100:
      raise ValueError("invalid value for min percent '%s'" % min_percent)
   elif not 0 <= max_percent <= 100:
      raise ValueError("invalid value for max percent '%s'" % max_percent)

   min_percent = float(min_percent) / 100.0
   max_percent = float(max_percent) / 100.0

   if len(image_data.shape) != 2:
      raise ValueError("input data is not an image")

   if num_points > numpy.size(image_data) or num_points < 0:
      num_points = 0.5 * numpy.size(image_data)

   num_per_col = int(float(num_points) / float(num_per_row) + 0.5)
   xsize, ysize = image_data.shape
   row_skip = float(xsize - 1) / float(num_per_row - 1)
   col_skip = float(ysize - 1) / float(num_per_col - 1)

   data = []
   for i in xrange(num_per_row):
      x = int(i * row_skip + 0.5)
      for j in xrange(num_per_col):
         y = int(j * col_skip + 0.5)
         data.append(image_data[x, y])
   data.sort()
   zmin = data[int(min_percent * len(data))]
   zmax = data[int(max_percent * len(data))]

   return zmin, zmax


def histogram_levels(scidata, contrast=0.001):
   csum = numpy.cumsum(numpy.histogram(scidata, int(scidata.max())+1, (0, int(scidata.max())+1))[0])
   cmax = scidata.size
   crange = cmax*contrast
   searchParam = [crange, cmax-crange]
   strminmax = csum.searchsorted(searchParam)
   strmin = strminmax[0]
   strmax = strminmax[1]
   return strmin, strmax

