package interesting;

import java.io.InputStream;
import java.lang.Exception;
import javafx.io.http.HttpRequest;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import interesting.model.Photo;
import interesting.parser.PhotoPullParser;
import interesting.view.FullImageView;
import interesting.view.ImageButton;

/**
 * Sample FX Script Application for viewing some of Flickr's Interesting Photos
 * Click on the photo to view larger photo.
 */

// TODO: get an apiKey from http://developer.yahoo.com/flickr
def apiKey = FX.getArgument("flickr_apikey");

// Application Width and Height
var stageX = 280.0;
var stageY = 140.0;
def stageWidth = 240;
def stageHeight = 320;

// Is running as Applet? If no, show close [X] button
var inBrowser = "true".equals(FX.getArgument("isApplet") as String);
var bgSuffix = "_x";
if(inBrowser) { bgSuffix = ""; }

// Is running in Mobile? If yes, load smaller 75 X 75 images
var isMobile = (FX.getProperty("javafx.me.profiles") != null);
var imgSuffix = "t"; // 100 on longest side thumb image
if(isMobile) { imgSuffix = "s"; } // 75 X 75 square image

// Photo-Grid Page Index
var page:Integer = 0;

// Information about all interesting photos
var photos: Photo[];

// Background Image
var bgImage = ImageView { 
    focusable: true
    image: Image {
        url: "{__DIR__}images/background{bgSuffix}.png"
    }
    onKeyPressed:function(e:KeyEvent) {
        if(e.code == KeyCode.VK_LEFT) {
            onBack();
        } else if(e.code == KeyCode.VK_RIGHT) {
            onNext();
        }
    }
}
bgImage.requestFocus();

// Dispose Application
var closeButton:ImageView = ImageButton { 
    
    x: stageWidth - 36
    y: 8
    normalImage: Image { url: "{__DIR__}images/close_n.png" }
    selectImage: Image { url: "{__DIR__}images/close_h.png" }
    visible: bind (not inBrowser)
    
    onMouseClicked: function(e) {
        javafx.lang.FX.exit();
    }
}

// Display next set of photos
var nextButton = ImageButton { 
    
    x: stageWidth - 42
    y: stageHeight - 23
    normalImage: Image { url: "{__DIR__}images/next_n.png" };
    selectImage: Image { url: "{__DIR__}images/next_h.png" };
            
    onMouseClicked: function(e) {
        onNext();
    }
}
function onNext() {
    fullImageView.show = false;
    page++; // Increment
    if(page >= 10) page = 0;
    updateImages();
}

// Display previous set of photos
var backButton = ImageButton { 
    
    x: stageWidth - 67
    y: stageHeight - 23
    normalImage: Image { url: "{__DIR__}images/back_n.png" };
    selectImage: Image { url: "{__DIR__}images/back_h.png" };
    
    onMouseClicked: function(e) {
        onBack();
    }
}
function onBack() {
    fullImageView.show = false;
    page--; // Decrement
    if(page < 0) page = 10;
    updateImages();
}

// Title and Status details
var titleText: Text;
var title = "";
var statusText: Text;
var status = "Loading Photos...";

// Initialize Photo-Grid
// Thumnail Bounds
var thumbBaseX = 21;
var thumbBaseY = 75;
var thumbSize = 64;
var thumbSpace = 3;

// To display thumb image
class ThumbImageView extends ImageView {
    
    override var fitWidth = thumbSize;
    override var fitHeight = thumbSize;
    
    var photo: Photo;
    
    public override var onMouseClicked = function(e:MouseEvent) {
        
        if(isMobile) { // Mobile: Resize 75 X 75 to fit screen
            fullImageView.image = image;
        } else { // Desktop: Load larger image with 240 on longest side
            fullImageView.image = Image {
                url: "http://farm{photo.farm}.static.flickr.com/{photo.server}/{photo.id}_{photo.secret}_m.jpg"
                placeholder: image
                backgroundLoading: true
            };
        }
        
        fullImageView.show = true;
    }
    
    public override var onMouseMoved = function(e:MouseEvent) {
        if(photo != null) { 
            if(photo.title.length() > 65) {
                title = "{photo.title.substring(0, 60)}...";
            } else {
                title = photo.title;
            }
        } else {
            title = "";
        }
    }
}

var thumbImageViews: ThumbImageView[]; // Thumbnail images
for(col in [0..2]) {
    for(row in [0..2]) {
        def thumbImageView = ThumbImageView { 
            x: thumbBaseX + (col * (thumbSize + thumbSpace))
            y: thumbBaseY + (row * (thumbSize + thumbSpace))
            fitWidth: thumbSize
            fitHeight: thumbSize
        }
        insert thumbImageView into thumbImageViews;
    }
}
var thumbImageViewGroup = Group {
    content: bind thumbImageViews
}

// Initialize fullscreen ImageView
var fullImageView = FullImageView {
    translateX: thumbBaseX
    translateY: thumbBaseY
    useEffects: not isMobile
    visible: false
}
fullImageView.onVisibleChange = function() {
    if(not fullImageView.visible) { title = ""; }
};

// Load image and data specified in given Photo object
function loadImage(photo: Photo, thumbImageView: ThumbImageView): Void { 
    thumbImageView.image = Image {
        url: "http://farm{photo.farm}.static.flickr.com/{photo.server}/{photo.id}_{photo.secret}_{imgSuffix}.jpg";
        width: thumbSize
        height: thumbSize
        backgroundLoading: true
        placeholder: thumbImageView.image
    };
    thumbImageView.photo = photo;
}

// Update images displayed in Photo-Grid
function updateImages() {
    
    for(i in [0..8]) {
        var photoIndex = (page*8) + i;
        loadImage(photos[photoIndex], thumbImageViews[i]);
    }
    
    title = "";
    status = "Page {page+1}";
}

// Application Titlebar
var titleBar = Rectangle {
    width: stageWidth
    height: 25
    fill: Color.TRANSPARENT
    visible: bind (not inBrowser)
    onMouseDragged: function(e) {
        stageX += e.dragX;
        stageY += e.dragY;
    }
}

// Set stage content based on status of api-key
var stageContent: Node[];

// If API-Key is empty, display error
if (apiKey == null) {
        
    var invalidAPIKey = [ 
        "This application", "requires an api key", 
        "from Flickr.", "", "Get yours from", 
        "http://developer.yahoo.com/flickr"
    ];
    
    var errorText: Text[];
    var lineIndex = 1;
    var fontSize = 16;
    var smooth = true;
    for(text in invalidAPIKey) {
        insert Text {
            x: thumbBaseX + thumbSpace
            y: thumbBaseY + (20 * lineIndex);
            font: Font { name: "Bitstream Vera Sans" size: fontSize }
            content: text
            fill: Color.WHITE
            smooth: smooth
        } into errorText;
        lineIndex++;
        if(lineIndex == 6) { 
            fontSize = 11; 
            smooth = false;
        }
    };
        
    stageContent = [
        bgImage, titleBar, closeButton, errorText, statusText
    ];
        
} else { // Retrieve photo information and display
    
    titleText = Text {
        x: thumbBaseX
        y: 43
        font: Font { name: "Bitstream Vera Sans" size: 11 }
        wrappingWidth: stageWidth * 0.8
        content: bind title
        fill: Color.WHITE
        smooth: true
        clip: Rectangle {
            x: thumbBaseX - 2
            y: 30
            width: stageWidth - 20
            height: 30
        }
    }
    
    statusText = Text {
        x: thumbBaseX + thumbSpace
        y: stageHeight - 12
        font: Font { name: "Bitstream Vera Sans" size: 11 }
        content: bind status
        fill: Color.WHITE
        smooth: true
        clip: Rectangle {
            x: thumbBaseX - 2
            y: stageHeight - 40
            width: stageWidth - 40
            height: 50
        }
    }
    
    stageContent = [
        bgImage, titleBar, nextButton, backButton, closeButton, 
        titleText, statusText, thumbImageViewGroup, fullImageView
    ];

    loadImageMetadata();    
}

function loadImageMetadata() {
    
    println("Loading image metadata...");   
    
    var httpRequestError: Boolean = false;
    
    // Submit HttpRequest    
    var request: HttpRequest = HttpRequest {
        
        location: "http://api.flickr.com/services/rest/?method="
            "flickr.interestingness.getList&api_key={apiKey}&per_page=92"
        method: HttpRequest.GET
       
        onException: function(exception: Exception) {
            exception.printStackTrace();
            alert("Error", "{exception}");
            httpRequestError = true;
        }
            
        onResponseCode: function(responseCode:Integer) {
            if (responseCode != 200) {
                println("failed, response: {responseCode} {request.responseMessage}");
            }
        }
                        
        onInput: function(input: java.io.InputStream) {
            
            try {
                                
                var parser = PhotoPullParser{};
                photos = parser.parse(input);
                if(parser.errorMessage.length() > 0) { 
                    alert("Error", parser.errorMessage);
                    httpRequestError = true; 
                }
                
            } finally {
                input.close();
            }
        }
            
        onDone: function() { 
            if(not httpRequestError) {
                updateImages(); 
            }
        }
    }
    
    request.enqueue();
}

function alert(alertTitle:String, msg:String): Void {
    println(msg);
    status = alertTitle;
    title = msg;
}

// Application User Interface
def stage = Stage {
    title: "Interesting Photos"
    resizable: false
    x: bind stageX with inverse
    y: bind stageY with inverse
    width: stageWidth
    height: stageHeight
    visible: true
    style: StageStyle.TRANSPARENT
    scene: Scene {
        content: Group {
            content: bind stageContent
            clip: Rectangle {
                width: stageWidth
                height: stageHeight
                arcWidth: 20
                arcHeight: 20
            }
        }
        fill: Color.TRANSPARENT
    }
}