/**
 * demo program for issue #5270
 */
package com.boardspace.dtest;

import java.util.Vector;

import com.codename1.ui.Button;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
// 
// drawing pdfs
//
//
import com.codename1.ui.Display;
import com.codename1.ui.Font;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.Image;
import com.codename1.ui.Stroke;
import com.codename1.ui.Toolbar;
import com.codename1.ui.Transform;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.geom.GeneralPath;
import com.codename1.ui.geom.Point;
import com.codename1.ui.geom.Rectangle;
import com.codename1.ui.layouts.Layout;
import com.codename1.ui.plaf.Style;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;


interface TestAble
{
	public void runTest(Test c,Graphics gc,int x,int y,int w,int h);
}

class GR
{

public static float[] transform(Transform tr,int x,int y)
{
	float fr[] = new float[] {x,y};
	float to[] = new float[2];
	tr.transformPoint(fr,to);
	return to;
}
public static void setOpacity(Graphics gr,double op) {
	gr.setAlpha(Math.max(0,Math.min(255,(int)(255*op))));
}
static boolean showClippedImage = true;
public static void drawImageRegion(Graphics graphics,Image img,
        int dx1, int dy1, int dx2, int dy2,
        int sx1, int sy1, int sx2, int sy2) {

    double scaleX = (double)(dx2 - dx1) / (sx2 - sx1);
    double scaleY = (double)(dy2 - dy1) / (sy2 - sy1);

    // Where would pixel (0,0) of the source land, given that
    // sx1 must map to dx1?
    int imgX = (int)(dx1 - sx1 * scaleX);
    int imgY = (int)(dy1 - sy1 * scaleY);

    int imgW = (int)(img.getWidth()  * scaleX);
    int imgH = (int)(img.getHeight() * scaleY);

    
    // Clip to dest rect so the rest of the scaled image is invisible
     {
     int[] oldClip = graphics.getClip();
     int tx = -0;
     int ty = 0;
     graphics.clipRect(tx+Math.min(dx1, dx2), ty+Math.min(dy1, dy2),Math.abs(dx2 - dx1), Math.abs(dy2 - dy1));
	if(showClippedImage)
	{
	graphics.setColor(0xffff00);
	setOpacity(graphics,0.5);
	graphics.fillRect(0,0,9999,9999);	// see where the clipping region really is
	setOpacity(graphics,1.0);
	}
	{
	graphics.drawImage(img, imgX, imgY, imgW, imgH);
	}
     graphics.setClip(oldClip);

    }
 
   	
    //
}
	
public static void drawImage(Graphics gc,Image img,
        int dx1, int dy1, int dx2, int dy2,
        int sx1, int sy1, int sx2, int sy2) 
	{

		drawImageRegion(gc,img,dx1,dy1,dx2,dy2,sx1,sy1,sx2,sy2);
}

}
class Polygon
{
	GeneralPath path = new GeneralPath();
	public Polygon() { }
	
	public void reset() { path.reset(); }
	
	public void addPoint(int x,int y) 
	{ 	if(path.getCurrentPoint()==null) 
			{ path.moveTo(x,y); } 
			else { path.lineTo(x,y); }
	}
	public void addPoint(Point p)
	{
		addPoint((int)p.getX(),(int)p.getY());
	}
	public void addPoint(float[]f)
	{
		addPoint((int)f[0],(int)f[1]);
	}
	public void fill(Graphics g)
	{
		g.fillShape(path);
	}
	public void frame(Graphics g)
	{
		Stroke stroke = new Stroke(
                1,
                Stroke.CAP_BUTT,
                Stroke.JOIN_ROUND, 1f
            );
 
		// Draw the shape
        g.drawShape(path, stroke);
		
	}
	public Rectangle getBounds() {
		return(path.getBounds());
	}
	public boolean contains(int i, int j) { return(path.getBounds().contains(i,j)); }
	/**
	 * add a rectangle as 4 new points in a polygon
	 * @param p
	 * @param rect
	 */
	public void addRect(Rectangle rect)
	{   int l = rect.getX();
		int t = rect.getY();
		int b = rect.getHeight()+t;
		int r = rect.getWidth()+l;
		addPoint(l,t);
		addPoint(r,t);
	    addPoint(r,b);
	    addPoint(l,b);
	    addPoint(l,t);	
	}
	public void framePolygon(Graphics inG)
	{
		if(inG!=null) { frame(inG); }
	}
	public void fillPolygon(Graphics inG)
	{
		if(inG!=null) { fill(inG); }
	}
}
interface LayoutManager {

}
class test_boardspace_graphics implements TestAble
{		
	public void runTest(Test tr,Graphics gc,int x,int y,int w,int h)
	{
		draw(gc,w,h,
				(Test.step&8)!=0,
				(Test.step&4)!=0,
				(Test.step&2)!=0,
				(Test.step&1)!=0,
				Test.step&0xF);
	}

Image htest = null;
Image vtest = null;
public Image prepare(Image pimage,int w,int h)
{	if(pimage==null || pimage.getWidth()!=w || pimage.getHeight()!=h)
		{
		pimage = Image.createImage(w,h);
		Graphics gc = pimage.getGraphics();
		gc.setColor(0xd0d0d0);
		gc.fillRect(0,0,w,h);
		gc.setColor(0);
		gc.drawLine(0,0,w,h);
		gc.drawLine(0,w,h,0);
		gc.setColor(0xff00);
		gc.fillRect(0,0,w,4);
		gc.fillRect(0,0,4,h);
		gc.fillRect(0,h-4,w,4);
		gc.fillRect(w-4,0,4,h);
		}
	return pimage;
}
public void draw(Graphics gc,int w,int h,boolean prescale,boolean globalClip,boolean imageClip,
		boolean rotate,int phase)
{	boolean localClip = false;
	boolean scaleThenClip = true;
	double imagexscale = 0.10;
	double imageyscale = 0.08;
	int imageW = (int)(w*imagexscale);
	int imageH = (int)(h*imageyscale);
	int imageS = Math.max(imageW,imageH);
	htest = prepare(htest,imageW,imageH); 
	vtest = prepare(vtest,imageH,imageW);
	int[] initialClip = gc.getClip();
	gc.setColor(0xff50000);
	gc.fillRect(0,0,w/2,h/2);
	gc.setColor(0x6ff0060);
	gc.fillRect(w/2,0,w/2,h/2);
	gc.setColor(0x6fa0f0f);
	gc.fillRect(0,h/2,w/2,h/2);
	gc.setColor(0xf85020);
	gc.fillRect(w/2,h/2,w/2,h/2);

	Vector<Polygon>images = new Vector<Polygon>();
	int ordinal=0;
	float scale = 1.2f;//2.5f;
	float effectiveScale = prescale ? scale : 1;
	double angle = 1.1;//Math.PI/10;
	int cx = w/6;
	int cy = h/4;
	int cw = w/2;
	int ch = h/2;
	int xspace = imageS*2/3;
	int yspace = imageS*9/13;
	int centerX = w/2;
	int centerY = h/2;
	if(globalClip)
		{
		gc.setColor(0xf000);
		gc.drawRect(cx-1,cy-1,cw+2,ch+2);
		gc.drawRect(cx-3,cy-3,cw+6,ch+6);
		}
	
	if(prescale && globalClip)
		{ 
		if(scaleThenClip)
		{	// clip will be scaled
		gc.scale(scale,scale);
			gc.setClip((int)(cx/scale),(int)(cy/scale),(int)(cw/scale),(int)(ch/scale));
		}
		else
		{
		gc.setClip(cx,cy,cw,ch);
			gc.scale(scale,scale);
		}
		}
	else if(prescale) { gc.scale(scale,scale); }
	else if(globalClip) { gc.setClip(cx,cy,cw,ch); }
	if(globalClip)
	{
		gc.setColor(0x101000);
		gc.fillRect(0,0,w,h);
	}
	int drawnCx = 0;
	int drawnCy = 0;
	for(int xp0=xspace/2,xstep=1;xp0<w/2;xp0+=xspace,xstep=-xstep)
				for(int yp0=yspace/2,ystep=1;yp0<h/2;yp0+=yspace,ystep=-ystep)
	{	int xp = xstep*xp0+centerX;
		int yp = ystep*yp0+centerY;
		//gc.drawLine(0,0,i,i);
		if(ordinal==0)
		{
			float[] drawnCenter = GR.transform(gc.getTransform(),xp,yp);
			drawnCx = (int)(drawnCenter[0]);
			drawnCy = (int)(drawnCenter[1]);
		}
		int[] clip = gc.getClip();
		ordinal++;
		//if(ordinal==149)
		{
		Image testImage = xstep*ystep>0 ? htest : vtest;
		boolean effectiveRotate = rotate && ordinal>1;
		int iW = testImage.getWidth();
		int iH = testImage.getHeight();
		int iSize = Math.min(imageW,imageH);
		int drawW = iW-(xstep<0 ? 0 : iW/3);
		int drawH = iH+(ystep<0 ? 0 : iH/4);
		float effectiveAngle = (float)(angle+0.01*ordinal);
		if(effectiveRotate) 
			{ 
			  gc.rotateRadians(effectiveAngle,xp,yp); 
			}
		if(localClip) { gc.clipRect(xp+2,yp+2,56,56); }
		Polygon p = new Polygon();
		Transform tr = gc.getTransform();
		if(effectiveRotate) 
			{ p.addPoint(GR.transform(tr,xp-10,yp-10)); 
			}
		p.addPoint(GR.transform(tr,xp,yp));
		p.addPoint(GR.transform(tr,xp+drawW,yp));
		p.addPoint(GR.transform(tr,xp+drawW,yp+drawH));
		p.addPoint(GR.transform(tr,xp,yp+drawH));
		p.addPoint(GR.transform(tr,xp,yp));
	
		{
		if(imageClip)
			{
			GR.drawImage(gc,testImage,xp,yp,xp+drawW,yp+drawH, iW/5,1, iW-iW/5-1,iH-iH/5);
			}
		else
			{
			gc.drawImage(testImage,xp,yp,drawW,drawH); 
			}
		}


		
		gc.setColor(0xffffff);
		gc.drawString("#"+ordinal,xp,yp+drawH/3);
		//gc.Text(xp+","+yp,xp,yp+drawH*2/3);
		images.addElement(p);
		// this is the actual point of failure.  In this context,
		// getclip + setclip is not idempotent
		if(localClip) { gc.setClip(clip); }
		if(effectiveRotate) 
			{ gc.rotateRadians(-effectiveAngle,xp,yp); 
			}
		if(globalClip)
		{	gc.setColor(0xffff00);
			GR.setOpacity(gc,0.1);
			int yx = (int)((cx+cw-iSize/2)/effectiveScale);
			int yy = (int)((cy+ch-iSize/2)/effectiveScale);
			gc.fillRect(yx,	yy,	iSize*2,iSize*2);
			GR.setOpacity(gc,1.0);
		}
	}}
	

	if(prescale && globalClip)
	{
		if(scaleThenClip)
		{	// clip will be scaled
			gc.scale(1/scale,1/scale);
			gc.setClip(initialClip);
		}
		else
		{	
			gc.setClip(initialClip); 
			gc.scale(1/scale,1/scale);
		}
	}
	else if(prescale) { gc.scale(1/scale,1/scale); }
	else if(globalClip) { gc.setClip(initialClip); }

	for(int i=0;i<images.size();i++)
	{
		Polygon p = images.elementAt(i);
		gc.setColor(0xa0a0a0);
		Rectangle r = p.getBounds();
		p.framePolygon(gc);
		gc.setColor(0xffff00);
		gc.drawString("."+(i+1),(int)(r.getX()+r.getWidth()/2),(int)(r.getY()+r.getHeight()/2));
		
	}
	gc.setColor(0xff);
	GR.setOpacity(gc,0.25);
	gc.drawLine(0,drawnCy,w,drawnCy);
	gc.drawLine(drawnCx,0,drawnCx,h);
	GR.setOpacity(gc,1.0);
		
	gc.setColor(0);
	gc.fillRect(w/10,0,w/2,h/15);
	gc.setColor(0xffffff);
	gc.drawString("phase "+phase+" prescale "+prescale+" globalclip "+globalClip+" imageClip "+imageClip+" rotate "+rotate,
			
			w/8,h/25);

}
}


class BorderLayout extends com.codename1.ui.layouts.BorderLayout implements LayoutManager
{
	
}

class Panel extends Container
{
	public Panel(Layout flowLayout,String uid)
	{	setLayout(flowLayout);
		setUIID(uid);
	}
}

class MasterToolBar extends Toolbar
{
	MasterToolBar()
	{
		super();
		setLayout(new BorderLayout());
		setUIID("TitleAreaMasterForm");	// our own structure with a margin on top

	}
}

class TabLayout extends com.codename1.ui.layouts.Layout
{	private int spacing = (int)(4*1.5);
	public void layoutContainer(Container parent) {
        int w = parent.getWidth();
        int h = parent.getHeight()-spacing*2;
        int nc = parent.getComponentCount();
		int sum = getFullWidth(parent);
		int squeeze = nc==0 ? 0 : (sum>w) ? (sum-w+nc)/nc : 0;
		int deficit = 0;
		for(int i=0,xpos=spacing;i<nc;i++) 
		{ com.codename1.ui.Component p = parent.getComponentAt(i);
		  p.setX(xpos);
		  p.setY(spacing);
		  p.setHeight(h);
		  int ww2 = prefw(parent,i);
		  int desired = ww2-squeeze+deficit;
		  int actual = Math.max(20, desired);
		  p.setWidth(actual);
		  deficit = desired-actual;
		  xpos += actual+spacing;
		}
	}
	
	int getFullWidth(Container parent)
	{	int nc = parent.getComponentCount();
		int h = parent.getHeight()-spacing*2;
		int sum = h/2;
		for(int i=0;i<nc;i++) 
		{ 
		  sum += prefw(parent,i)+spacing; 
		}
		return(sum);
	}
	// this is an ad-hoc calculation to find the preferred width for an icon
	// assuming it will be scaled to the height of the parent.  The h/6 factor
	// accounts for wider horizontal margins than vertical, not sure where they
	// come from.
	int prefw(Container parent, int i)
	{	int h = parent.getHeight()-spacing*2;
		Dimension dim = parent.getComponentAt(i).getPreferredSize();
		int inc = (int)(h*((double)dim.getWidth()/dim.getHeight())+h/6);
		return inc;
	}
	int getFullHeight(Container parent)
	{	int nc = parent.getComponentCount();
		// use font height as the basic scale metric
		Font f = parent.getStyle().getFont();
		int fs = f.getSize();
		int max = (int)(fs*2.2);
		//G.print("FontManager "+f+" sz ",fs," h ",max);
		for(int i=0;i<nc;i++) { max = Math.max(parent.getComponentAt(i).getPreferredSize().getHeight(),max); }
		return(max);
	}
	public Dimension getPreferredSize(Container parent) {
		
		Dimension dim =new Dimension(getFullWidth(parent),getFullHeight(parent));
		return(dim);
	}

}

@SuppressWarnings("rawtypes")
class MasterForm extends Form 
{	static MasterForm masterForm = null;
	public MasterForm()
	{	
	}
	
}
class NoLayout extends Layout
{

	public void layoutContainer(Container parent) {
		for(int i=0;i<parent.getComponentCount();i++)
		{
			Component c = parent.getComponentAt(i);
			c.setWidth(parent.getWidth());
			c.setHeight(parent.getHeight());
		}
	}

	public Dimension getPreferredSize(Container parent) {
		return new Dimension(parent.getWidth(),parent.getHeight());
	}
	
};

@SuppressWarnings("rawtypes")
class Test extends Component implements ActionListener<ActionEvent>
{	Form form = null;
	TestAble current = null;
	Test(Form f)
	{	form = f;		
		Toolbar tb = f.getToolbar();
		Dimension tbd = tb.getPreferredSize();
		setPreferredSize(new Dimension(f.getWidth(),f.getHeight()-tbd.getHeight()));
		current = new test_boardspace_graphics();
	}
	boolean change = false;
	int changes = 0;
	public static int step =0;
	
	public void paint(Graphics g)
	{	int w = getWidth();
		int h = getHeight();
		current.runTest(this,g,0,0,w,h);
	}
	public int getAbsoluteX()
	{	return getAbsoluteX(getParent());
	}
	public int getAbsoluteY()
	{	return getAbsoluteY(getParent());
	}
	public int getAbsoluteX(Container p)
	{	return (p==null) ? 0 : p.getX() + getAbsoluteX(p.getParent());
	}
	public int getAbsoluteY(Container p)
	{	return (p==null) ? 0 : p.getY() + getAbsoluteY(p.getParent());
	}
	public void actionPerformed(ActionEvent evt) {
		if(changes==0) {		change = true; }
		changes++;
	}
	public void pointerPressed(int x,int y)
	{
		if(changes==0) {		change = true; }
		changes++;
		step++;
	}
}
@SuppressWarnings("rawtypes")
public class Dtest{

private Form current;
@SuppressWarnings("unused")
private Resources theme;



public void init(Object context) {
    theme = UIManager.initFirstTheme("/theme");
    // Pro only feature, uncomment if you have a pro subscription
    // Log.bindCrashProtection(true);
}
public Toolbar toolbar = null;

public void start() {
    
    if(current != null){
        current.show();
    }
    MasterForm hi = new MasterForm();
    MasterToolBar toolBar = new MasterToolBar();
    hi.setToolbar(toolBar);
	Panel tabs = new Panel(new TabLayout(),"ContainerMasterForm");
	Panel menus = new Panel(new TabLayout(),"ContainerMasterForm");
	Panel centers = new Panel(new TabLayout(),"ContainerMasterForm");

	Style s = toolBar.getStyle();
	s.setMargin(0,0,0,0);			// remove the margin except on ios
	s.setPadding(0,0,0,0);

	toolBar.add("West",tabs);
	toolBar.add("East",menus);
	toolBar.add("Center",centers);  
	

	
	
    
	Button b1 = new Button("1 button 1");
	Button b2 = new Button("2 button 2");
	tabs.add(b1);
	tabs.add(b2);
    Test can = new Test(hi);
    hi.show();
    b1.addActionListener(can);
    b2.addActionListener(can);
    hi.addComponent(can);
    can.setVisible(true);
}
public void stop() {
    current = Display.getInstance().getCurrent();
}

public void destroy() {
}
}



