/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                                                                         *
 *   AndroidWorld Library, Copyright 2011 Bryan Chadwick                   *
 *                                                                         *
 *   FILE: ./android/image/Scene.java                                      *
 *                                                                         *
 *   This file is part of AndroidWorld.                                    *
 *                                                                         *
 *   AndroidWorld 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.              *
 *                                                                         *
 *   AndroidWorld 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 AndroidWorld.  If not, see <http://www.gnu.org/licenses/>. *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

package android.image;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.world.Posn;

/**
 * <style type='text/css'><!--
 *    .com{ font-style: italic; color: #880000; }
 *    .keyw{ font-weight: bold; color: #000088; }
 *    .num{ color: #00AA00; }
 *    .str{ color: #CC00AB; }
 *    .prim{ color: #0000FF; }
 *    img.example{ padding-left: 50px; padding-bottom: 30px; }
 *  --></style>
 * 
 * An abstract Class representing a Scene (a cropped <code>Image</code>).  Images
 * can be placed on a <code>Scene</code> at a specific location, resulting in a
 * new <code>Scene</code>. 
 * 
 * <pre>
 *    <span class='keyw'>new</span> EmptyScene(<span class='num'>48</span>, <span class='num'>48</span>).placeImage(<span class='keyw'>new</span> Triangle(<span class='num'>32</span>, <span class='str'>"solid"</span>, <span class='str'>"red"</span>), <span class='num'>24</span>, <span class='num'>24</span>)</pre>
 * <img class="example" src="test/images/scene-1.png" />
 * <br />
 *
 * <pre>
 *    <span class='keyw'>new</span> EmptyScene(<span class='num'>48</span>, <span class='num'>48</span>).placeImage(<span class='keyw'>new</span> Triangle(<span class='num'>64</span>, <span class='str'>"solid"</span>, <span class='str'>"red"</span>), <span class='num'>24</span>, <span class='num'>24</span>)</pre>
 * <img class="example" src="test/images/scene-2.png" />
 * <br /> 
 * 
 * <pre>
 *    <span class='keyw'>new</span> EmptyScene(<span class='num'>48</span>, <span class='num'>48</span>).addLine(<span class='num'>0</span>, <span class='num'>0</span>, <span class='num'>48</span>, <span class='num'>48</span>, <span class='str'>"blue"</span>)</pre>
 * <img class="example" src="test/images/addline-1.png" />
 * <br/>
 * 
 * <pre>
 *    <span class='keyw'>new</span> EmptyScene(<span class='num'>48</span>, <span class='num'>48</span>).addLine(<span class='num'>4</span>, <span class='num'>24</span>, <span class='num'>44</span>, <span class='num'>24</span>, <span class='str'>"green"</span>)</pre>
 * <img class="example" src="test/images/addline-2.png" />
 * <br/>
 * 
 * <pre>
 *    <span class='keyw'>new</span> EmptyScene(<span class='num'>50</span>, <span class='num'>50</span>)
 *         .placeImage(<span class='keyw'>new</span> Overlay(<span class='keyw'>new</span> Circle(<span class='num'>20</span>, <span class='str'>"outline"</span>, <span class='str'>"black"</span>),
 *                                 <span class='keyw'>new</span> Circle(<span class='num'>20</span>, <span class='str'>"solid"</span>, <span class='str'>"wheat"</span>)), <span class='num'>25</span>, <span class='num'>25</span>)
 *         .placeImage(<span class='keyw'>new</span> Circle(<span class='num'>5</span>, <span class='str'>"solid"</span>, <span class='str'>"lightblue"</span>), <span class='num'>18</span>, <span class='num'>20</span>)
 *         .placeImage(<span class='keyw'>new</span> Rectangle(<span class='num'>10</span>, <span class='num'>3</span>, <span class='str'>"solid"</span>, <span class='str'>"lightblue"</span>), <span class='num'>33</span>, <span class='num'>20</span>)
 *         .placeImage(<span class='keyw'>new</span> Ellipse(<span class='num'>20</span>, <span class='num'>8</span>, <span class='str'>"solid"</span>, <span class='str'>"red"</span>), <span class='num'>25</span>, <span class='num'>35</span>)</pre>
 * <img class="example" src="test/images/face.png" />
 * <br/>
 */
public abstract class Scene extends Image{
    
    protected Scene(){ super(0,0); }

    /** Draw the scene into a Graphics */
    public abstract void paint(Canvas c, int x, int y);
    
    /** Place another Image on top of this Scene at (x,y) */
    public Scene placeImage(Image i, double x, double y){
        return new Placed(i,(int)x,(int)y,this);    
    }
    /** Place another Image on top of this Scene at (x,y) */
    public Scene placeImage(Image i, int x, int y){ return new Placed(i,x,y,this); }
    /** Place another Image on top of this Scene at the given Posn */
    public Scene placeImage(Image i, Posn p){ return new Placed(i,p.x,p.y,this); }

    /** Add a line to this Scene from (x,y) to (xx, yy) */
    public Scene addLine(int x, int y, int xx, int yy, String color){
        return this.addLine((double)x, y, xx, yy, color);    
    }
    /** Add a line to this Scene from (x,y) to (xx, yy) */
    public Scene addLine(double x, double y, double xx, double yy, String color){
        return this.placeImage(new Line(xx-x, yy-y, color),
                       (xx+x)/2, (yy+y)/2);    
    }
    /** Add a line to this Scene from the first Posn to the second */
    public Scene addLine(Posn p1, Posn p2, String color){
        return this.placeImage(new Line(p2.x-p1.x, p2.y-p1.y, color),
                       (p2.x+p1.x)/2, p2.y+p1.y/2);    
    }
    
    /** Represents an Image Placed on top of a Scene at offset X/Y */
    private static class Placed extends Scene{
        private Image img;
        private double x;
        private double y;
        private Scene next;
                
        Placed(Image img, int x, int y, Scene next){
            this(img, (double)x, y, next);
        }
        Placed(Image img, double x, double y, Scene next){
            this.img = img;
            this.x = x;
            this.y = y;
            this.next = next;
        }
        /** Paint the next scene, then place the image on top */
        public void paint(Canvas c, int xx, int yy){
            next.paint(c,xx,yy);
            img.paint(c,round(xx+x),round(yy+y));
        }
        
        /** Calculate the width of the combined Scene/Image */
        public int width(){ return next.width(); }
        /** Calculate the height of the combined Scene/Image */
        public int height(){ return next.height(); }
    }

    /** Save this Scene to a File */    
    public boolean toFile(String name){
        try{
            RasterImage rast = this.rasterize();
            int dot = name.lastIndexOf('.');
            String ext = name.substring(dot+1);
            java.io.FileOutputStream out = new java.io.FileOutputStream(name);
            
            // Android appears to only have JPEG and PNG
            rast.img.compress((ext.toLowerCase().equals("png"))?
                    Bitmap.CompressFormat.PNG:
                        Bitmap.CompressFormat.JPEG, 100, out);
            return true;
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }
}