/*
 * Copyright (c) 2009, Takeyuki Nagao
 * 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.
 *    
 * 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 HOLDER 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.
 */

package jp.sourceforge.dvibrowser.dvicore.render;

import jp.sourceforge.dvibrowser.dvicore.DviException;
import jp.sourceforge.dvibrowser.dvicore.DviRect;
import jp.sourceforge.dvibrowser.dvicore.DviResolution;
import jp.sourceforge.dvibrowser.dvicore.api.GammaCorrector;
import jp.sourceforge.dvibrowser.dvicore.api.ImageDevice;
import jp.sourceforge.dvibrowser.dvicore.gui.swing.ViewSpec;


public class IntRGBImage
{
  private final int [] buf;
  private final int width;
  private final int height;

  public IntRGBImage(int width, int height) {
    this.buf = new int [width * height];
    this.width = width;
    this.height = height;
  }

  public IntRGBImage(int [] buf, int width, int height) {
    this.buf = buf;
    this.width = width;
    this.height = height;
  }

  public int [] getBuffer() { return buf; }

  public int width() { return width; }
  public int height() { return height; }

  public void fill(int c) {
    for (int i=0; i<buf.length; i++)
//      buf[i] = 0xff000000 | c;
      buf[i] = c;
  }

  public ImageDevice getImageDevice(DviResolution res, GammaCorrector gc) {
    return new ImageDeviceImpl(res, gc);
  }
  public ImageDevice getImageDevice(DviResolution res) {
    return getImageDevice(res, null);
  }

  private class ImageDeviceImpl
  extends AbstractDevice
  implements ImageDevice
  {
    private final GammaCorrector originalGammaCorrector;
    private GammaCorrector gammaCorrector;
    private int maxval;
    protected ImageDeviceImpl(DviResolution res, GammaCorrector gammaCorrector) {
      super(res);
      this.originalGammaCorrector = (gammaCorrector == null) ? ViewSpec.getDefaultGammaCorrector() : gammaCorrector;
      if (originalGammaCorrector == null)
        throw new IllegalStateException("Unable to determine the gamma corrector.");
    }

    public DviRect getBounds() {
      return new DviRect(-point.x, -point.y, width, height);
    }

    public void begin(int maxval) {
      this.maxval = maxval;
      gammaCorrector = GammaCorrectorCache.wrap(originalGammaCorrector);
    }

    public void end() {
    }

    private int ptr = 0;
//    private int gw;
//    private int gh;
    public boolean beginImage(int w, int h)
    throws DviException
    {
//      gw = w;
//      gh = h;
      ptr = point.x + point.y * width;
      return true;
    }
    public void endImage() {
    }

    public void putLine(int [] l_buf, int off, int len)
    throws DviException
    {
      final int color = getColor().toIntRGB();
      for (int i=0; i<len; i++) {
        final int alpha10 = gammaCorrector.correctGamma(l_buf[off + i], maxval);
        if (alpha10 != 0)
          buf[ptr + i] = blend(buf[ptr + i], color, alpha10);
      }
      ptr += width;
    }
  }

  private static int blendARGB(int c1, int c2, final int alpha10) {
    int r, g, b;

    b = c1 & 0xff;
    b += (alpha10 * ((c2 & 0xff) - b)) >>> 10;
    b &= 0xff;
    c1 >>>= 8;
    c2 >>>= 8;

    g = c1 & 0xff;
    g += (alpha10 * ((c2 & 0xff) - g)) >>> 10;
    g &= 0xff;
    c1 >>>= 8;
    c2 >>>= 8;

    r = c1 & 0xff;
    r += (alpha10 * ((c2 & 0xff) - r)) >>> 10;
    r &= 0xff;

    return 0xff000000 | (r << 16) | (g << 8) | b;
  }
  
  private static int blend(int c1, int c2, final int alpha10) {
	    int r, g, b;

	    b = c1 & 0xff;
	    b += (alpha10 * ((c2 & 0xff) - b)) >>> 10;
	    b &= 0xff;
	    c1 >>>= 8;
	    c2 >>>= 8;

	    g = c1 & 0xff;
	    g += (alpha10 * ((c2 & 0xff) - g)) >>> 10;
	    g &= 0xff;
	    c1 >>>= 8;
	    c2 >>>= 8;

	    r = c1 & 0xff;
	    r += (alpha10 * ((c2 & 0xff) - r)) >>> 10;
	    r &= 0xff;

	    return (r << 16) | (g << 8) | b;
	  }

}
//BenchMark: dvidump: 535 samples in 19.174 sec. 27.902 samples/sec.  35.839 msec./sample.
