/*
	Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
	и других спецификаций для функционирования компактных приложений на языке
	Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

	Copyright © 2016, 2019 Малик Разработчик

	Это свободная программа: вы можете перераспространять ее и/или изменять
	ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
	в каком она была опубликована Фондом свободного программного обеспечения;
	либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

	Эта программа распространяется в надежде, что она будет полезной,
	но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
	или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
	общественной лицензии GNU.

	Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
	вместе с этой программой. Если это не так, см.
	<https://www.gnu.org/licenses/>.
*/


package javax.microedition.lcdui;

import java.io.*;
import malik.emulator.fileformats.*;
import malik.emulator.fileformats.graphics.*;
import malik.emulator.io.j2me.*;
import malik.emulator.io.jar.*;
import malik.emulator.media.graphics.*;

public class Image extends Object
{
	private static final long MAX_AREA = 1L << 20;

	public static Image createImage(int width, int height)
	{
		int i;
		long area;
		int[] pixels;
		if(width <= 0 || height <= 0)
		{
			throw new IllegalArgumentException("Image.createImage: " +
					"размеры могут быть только положительными.");
		}
		if((area = ((long) width) * (long) height) > MAX_AREA)
		{
			throw new IllegalArgumentException("Image.createImage: " +
					"размеры очень большие.");
		}
		for(pixels = new int[i = (int) area]; i-- > 0; pixels[i] = -1);
		return new Image(new GraphicBuffer(pixels, 0, width, width, height), true);
	}

	public static Image createImage(Image src)
	{
		int area;
		int width;
		int height;
		int[] pixels;
		GraphicBuffer buffer;
		if(src == null)
		{
			throw new NullPointerException("Image.createImage: " +
					"параметр src равен нулевой ссылке.");
		}
		if(!src.mutable)
		{
			return src;
		}
		Array.copy((buffer = src.buffer).getPixels(), 0, pixels = new int[area =
				(width = buffer.getWidth()) * (height = buffer.getHeight())], 0, area);
		return new Image(new GraphicBuffer(pixels, 0, width, width, height));
	}

	public static Image createImage(Image src, int left, int top, int width, int height,
			int transform)
	{
		int lim;
		int len;
		int w;
		int h;
		GraphicBuffer buffer;
		if(src == null)
		{
			throw new NullPointerException("Image.createImage: " +
					"параметр src равен нулевой ссылке.");
		}
		if(width <= 0 || height <= 0)
		{
			throw new IllegalArgumentException("Image.createImage: " +
					"размеры могут быть только положительными.");
		}
		if((lim = left + width) > (len = w = src.getWidth()) ||
				lim < left || left > len || left < 0 ||
				(lim = top + height) > (len = h = src.getHeight()) ||
				lim < top || top > len || top < 0)
		{
			throw new IllegalArgumentException("Image.createImage: " +
					"заданная прямоугольная область выходит за пределы исходного изображения.");
		}
		if((transform = Graphics.spriteTransformToMalik(transform)) < 0)
		{
			throw new IllegalArgumentException("Image.createImage: " +
					"недопустимое значение параметра transform.");
		}
		if((!src.mutable) && left == 0 && top == 0 && width == w && height == h &&
				transform == RasterCanvas.TRANSFORM_NONE)
		{
			return src;
		}
		buffer = (transform & 1) == 0 ?
				new GraphicBuffer(new int[width * height], 0, width, w = width, h = height) :
				new GraphicBuffer(new int[width * height], 0, height, w = height, h = width);
		(new RasterCanvas(buffer)).drawPixelsArea(0, 0, w, h,
				src.buffer, left, top, width, height, transform, 0, 0, w, h, true);
		return new Image(buffer);
	}

	public static Image createImage(byte[] src, int offset, int length)
	{
		int i;
		int lim;
		int len;
		int[] pixels;
		InputStream stream;
		ImageDecoder decoder;
		GraphicBuffer buffer;
		if(src == null)
		{
			throw new NullPointerException("Image.createImage: " +
					"параметр src равен нулевой ссылке.");
		}
		if((lim = offset + length) > (len = src.length) ||
				lim < offset || offset > len || offset < 0)
		{
			throw new ArrayIndexOutOfBoundsException("Image.createImage: " +
					"индекс выходит из диапазона.");
		}
		try
		{
			if((decoder = ImplementationManager.getImageDecoder(stream =
					new ByteArrayInputStream(src, offset, length))) == null)
			{
				throw new IllegalArgumentException("Image.createImage: " +
						"ошибка декодирования изображения.");
			}
			decoder.loadFromInputStream(stream);
		}
		catch(IOException e)
		{
			throw new IllegalArgumentException("Image.createImage: " +
					"ошибка декодирования изображения.");
		}
		if(decoder.isEmpty())
		{
			throw new IllegalArgumentException("Image.createImage: " +
					"ошибка декодирования изображения.");
		}
		buffer = new GraphicBuffer(pixels = decoder.getPixels(), 0,
				i = decoder.getWidth(), i, decoder.getHeight());
		if(!decoder.isAlphaSupported())
		{
			for(i = pixels.length; i-- > 0; pixels[i] |= 0xff000000);
		}
		return new Image(buffer);
	}

	public static Image createImage(InputStream stream)
			throws IOException
	{
		int i;
		int[] pixels;
		ImageDecoder decoder;
		GraphicBuffer buffer;
		if(stream == null)
		{
			throw new NullPointerException("Image.createImage: " +
					"параметр stream равен нулевой ссылке.");
		}
		if((decoder = ImplementationManager.getImageDecoder(stream)) == null)
		{
			throw new InvalidDataFormatException("Image.createImage: " +
					"неизвестный формат изображения.");
		}
		decoder.loadFromInputStream(stream);
		if(decoder.isEmpty())
		{
			throw new InvalidDataFormatException("Image.createImage: " +
					"неизвестный формат изображения.");
		}
		buffer = new GraphicBuffer(pixels = decoder.getPixels(), 0,
				i = decoder.getWidth(), i, decoder.getHeight());
		if(!decoder.isAlphaSupported())
		{
			for(i = pixels.length; i-- > 0; pixels[i] |= 0xff000000);
		}
		return new Image(buffer);
	}

	public static Image createImage(String resourceName)
			throws IOException
	{
		int i;
		int[] pixels;
		InputStream stream;
		ImageDecoder decoder;
		GraphicBuffer buffer;
		if(resourceName == null)
		{
			throw new NullPointerException("Image.createImage: " +
					"параметр resourceName равен нулевой ссылке.");
		}
		if((stream = resourceName.getClass().getResourceAsStream(
				resourceName.length() <= 0 || resourceName.charAt(0) != '/' ?
				(resourceName = "/".concat(resourceName)) : resourceName)) == null)
		{
			throw new ResourceNotFoundException("Image.createImage: " +
					"ресурс " + resourceName + " не найден.");
		}
		if((decoder = ImplementationManager.getImageDecoder(stream)) == null)
		{
			throw new InvalidDataFormatException("Image.createImage: " +
					"неизвестный формат изображения.");
		}
		decoder.loadFromInputStream(stream);
		if(decoder.isEmpty())
		{
			throw new InvalidDataFormatException("Image.createImage: " +
					"неизвестный формат изображения.");
		}
		buffer = new GraphicBuffer(pixels = decoder.getPixels(), 0,
				i = decoder.getWidth(), i, decoder.getHeight());
		if(!decoder.isAlphaSupported())
		{
			for(i = pixels.length; i-- > 0; pixels[i] |= 0xff000000);
		}
		return new Image(buffer);
	}

	public static Image createRGBImage(int[] src, int width, int height, boolean alpha)
	{
		int i;
		long area;
		int[] pixels;
		if(src == null)
		{
			throw new NullPointerException("Image.createRGBImage: " +
					"параметр src равен нулевой ссылке.");
		}
		if(width <= 0 || height <= 0)
		{
			throw new IllegalArgumentException("Image.createRGBImage: " +
					"размеры могут быть только положительными.");
		}
		if((area = ((long) width) * (long) height) > MAX_AREA)
		{
			throw new IllegalArgumentException("Image.createRGBImage: " +
					"размеры очень большие.");
		}
		if(area > (long) src.length)
		{
			throw new ArrayIndexOutOfBoundsException("Image.createRGBImage: " +
					"индекс выходит из диапазона.");
		}
		Array.copy(src, 0, pixels = new int[i = (int) area], 0, i);
		if(!alpha)
		{
			for(; i-- > 0; pixels[i] |= 0xff000000);
		}
		return new Image(new GraphicBuffer(pixels, 0, width, width, height));
	}


	private boolean mutable;
	private GraphicBuffer buffer;

	private Image(GraphicBuffer buffer)
	{
		this.mutable = false;
		this.buffer = buffer;
	}

	private Image(GraphicBuffer buffer, boolean mutable)
	{
		this.mutable = mutable;
		this.buffer = buffer;
	}

	public void getRGB(int[] dst, int offset, int scanlength,
			int left, int top, int width, int height)
	{
		int i;
		int lim;
		int len;
		int length;
		int srcScan;
		int srcLine;
		int dstLine;
		int[] src;
		GraphicBuffer buffer;
		if(dst == null)
		{
			throw new NullPointerException("Image.getRGB: " +
					"параметр dst равен нулевой ссылке.");
		}
		if(width <= 0 || height <= 0)
		{
			return;
		}
		if((lim = left + width) > (len = (buffer = this.buffer).getWidth()) ||
				lim < left || left > len || left < 0 ||
				(lim = top + height) > (len = buffer.getHeight()) ||
				lim < top || top > len || top < 0)
		{
			throw new IllegalArgumentException("Image.getRGB: " +
					"заданная прямоугольная область выходит за пределы растровой канвы.");
		}
		if(Math.abs(scanlength) < width)
		{
			throw new IllegalArgumentException("Image.getRGB: " +
					"длина линии сканирования не может быть меньше ширины.");
		}
		if(scanlength >= 0)
		{
			i = 0;
			length = width + (height - 1) * scanlength;
		} else
		{
			i = (-scanlength) * (height - 1);
			length = width + i;
		}
		offset -= i;
		if((lim = offset + length) > (len = dst.length) ||
				lim < offset || offset > len || offset < 0)
		{
			throw new ArrayIndexOutOfBoundsException("Image.getRGB: " +
					"индекс выходит из диапазона.");
		}
		offset += i;
		src = buffer.getPixels();
		srcLine = buffer.getOffset() + left + top * (srcScan = buffer.getScanlength());
		dstLine = offset;
		for(i = 0; i < height; srcLine += srcScan, dstLine += scanlength, i++)
		{
			Array.copy(src, srcLine, dst, dstLine, width);
		}
	}

	public boolean isMutable()
	{
		return mutable;
	}

	public int getWidth()
	{
		return buffer.getWidth();
	}

	public int getHeight()
	{
		return buffer.getHeight();
	}

	public Graphics getGraphics()
	{
		if(!mutable)
		{
			throw new IllegalStateException("Image.getGraphics: " +
					"изображение неизменяемо.");
		}
		return new Graphics(buffer);
	}

	public final GraphicBuffer getBuffer()
	{
		return buffer;
	}
}
