License text

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER 
 * Copyright  2008, 2010 Oracle and/or its affiliates.  All rights reserved. 
 * Use is subject to license terms.
 * 
 * This file is available and licensed under the following license:
 * 
 * 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.
 *
 *   * Neither the name of Oracle Corporation nor the names of its contributors 
 *     may be used to endorse or promote products derived from this software 
 *     without specific prior written permission. 
 *
 * 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 
 * OWNER 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 tweeter.view;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Exception;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.data.Pair;
import javafx.io.http.HttpHeader;
import javafx.io.http.HttpRequest;
import javafx.io.http.URLConverter;
import javafx.scene.control.TextBox;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import tweeter.model.Status;
import tweeter.parser.StatusParser;
import tweeter.view.AbstractView;
import tweeter.view.ImageButton;
import tweeter.view.list.ListItem;
import tweeter.view.list.ListView;
import tweeter.view.TweeterView;
import javafx.stage.Alert;
import javafx.scene.layout.HBox;

// @author Rakesh Menon


public class FriendsView extends AbstractView {
    
    def sttextbox_layoutX = 12;
    def sttextbox_layoutY = 24;
    def sttextbox_widhtpadding = 60;
    def stbtn_layoutXpadding = 42;
    def stbtn_layoutY = 20;
    def statuslist_layoutX = 5;
    def statuslist_layoutY = 62;
    def statuslist_heightpadding = 105;
    def linestartX = 5;
    def linestartY = 55;
    def lineendX_padding = 6;
    def lineendY = 55;

    public var user:String;
    public var passwd:String;
    public var loggedIn = false;
    public var onException:function(message:String) = null;

    override var show = true on replace {
        if(visible) {
            statusTextBox.requestFocus();
        }
    };

    var statusButton:ImageButton;
    var statusTextBox:TextBox;
    
    var textImgHBox : HBox = HBox {
        layoutX: sttextbox_layoutX
        layoutY: sttextbox_layoutY
        content: [
            // TextBox-Status
        statusTextBox = TextBox {
            layoutX: sttextbox_layoutX
            layoutY: sttextbox_layoutY
            width: bind (TweeterView.width - sttextbox_widhtpadding)
            promptText: "My Status"
            action: function() {
                statusTextBox.commit();
                addStatus("{statusTextBox.text}");
                statusTextBox.text = "";
            }
        },
            // Image Button
        statusButton = ImageButton {
            layoutX: bind (TweeterView.width - stbtn_layoutXpadding)
            layoutY: stbtn_layoutY
            normalImage: TweeterView.theme.statusImage
            onMousePressed: function(e) {
                statusTextBox.commit();
                addStatus("{statusTextBox.rawText}");
                statusTextBox.text = "";
            }
        }
        ]
    };


    // Status List Items
    var statusListItem : ListItem[];
    var statusList = ListView {
        layoutX: statuslist_layoutX
        layoutY: statuslist_layoutY
        height: bind TweeterView.height - statuslist_heightpadding
        listItem: bind statusListItem
    };
    
    var updateTimeline = Timeline {
        repeatCount: Timeline.INDEFINITE
        keyFrames: [
            KeyFrame {
                time: 60s
                action:function() {
                    updateStatusList();
                }
            }
        ]
    };

    public function start():Void {
        loggedIn = true;
        updateStatusList();
        if(not updateTimeline.running) {
            updateTimeline.play();
        }
    }

    function updateStatusList():Void {
        var httpHeader = HttpHeader.basicAuth(user, passwd);
        
        var httpRequest = HttpRequest {
            location: "http://www.twitter.com/statuses/friends_timeline.xml"
            headers: [ httpHeader ]
            onResponseCode:function(respCode:Integer):Void {
                if(respCode == 401) {
                     Alert.inform("Authentication Failed");
                }
                 if(respCode == 400) {
                     Alert.inform("Rate Limiting Error, Please Log-in some other Time.");
                }
            }

            onInput:function(is:InputStream) {
                try {
                    StatusParser{ updateStatus: updateStatus }.parse(is);
                } finally {
                    is.close();
                }
            }

            onException:function(ex:java.lang.Exception) {
                onException("{ex.getMessage()}");
                show = false;
                loggedIn = false;
            }
        };
        httpRequest.start();
    }

    public function updateStatus(statuses:Status[]):Void {
        delete statusListItem;

        var index = 0;
        for(status in statuses) {
            var listItem = ListItem {
                listView: statusList
                canDelete: status.user.screenName.equals(user)
                onDelete: deleteStatus
            };
            listItem.setStatus(status);
            insert listItem into statusListItem;
            index++;
        };
    }

    function addStatus(message:String):Void {
        if(not ((message != null) and (message.trim().length() > 0))) {
            return;
        }
        
        var httpHeader = HttpHeader.basicAuth(user, passwd);
        var httpRequest = HttpRequest {

            location: "http://twitter.com/statuses/update.xml"
            headers: [ httpHeader ]
            method: HttpRequest.POST
            onInput:function(is:InputStream) {
                is.close();
            }
            onOutput:function(os:OutputStream) {
                var urlConverter = URLConverter{};
                var pair = Pair {
                    name: "status"
                    value: ListItem.trimString("{message}", 140)
                };
                var encodedMessage = urlConverter.encodeParameters([pair]);
                os.write(encodedMessage.getBytes());
                os.close();
            }

            onException: function(ex: Exception) {
                onException("{ex.getMessage()}");
            }

            onDone: function() {
                updateStatusList();
            }
        };
        httpRequest.start();
    }

    function deleteStatus(id:String):Void {
        if(not ((id != null) and (id.trim().length() > 0))) {
            return;
        }

        var httpHeader = HttpHeader.basicAuth(user, passwd);
        var httpRequest = HttpRequest {

            location: "http://twitter.com/statuses/destroy/{id}.xml"
            headers: [ httpHeader ]
            method: HttpRequest.POST
            onInput:function(is:InputStream) {
                is.close();
            }
            onOutput:function(os:OutputStream) {
                os.close();
            }

            onException: function(ex: java.lang.Exception) {
                onException("{ex.getMessage()}");
            }
            onDone:function() {
                updateStatusList();
            }
        };
        httpRequest.start();
    }

    public function logout():Void {
        if(not loggedIn) { return; }
        
        updateTimeline.stop();
        delete statusListItem;
        loggedIn = false;
        
        var httpHeader = HttpHeader.basicAuth(user, passwd);

        user = "";
        passwd = "";

        var httpRequest = HttpRequest {

            location: "http://twitter.com/account/end_session.xml"
            headers: [ httpHeader ]
            method: HttpRequest.POST
            onOutput:function(os:OutputStream) {
                os.close();
            }
            onException:function(ex:java.lang.Exception) {
                onException("{ex.getMessage()}");
            }
        };
        httpRequest.start();
    }

        var line = Line {
            startX: linestartX
            startY: linestartY
            endX: bind TweeterView.width - lineendX_padding
            endY: lineendY
            stroke: bind Color.web("#{TweeterView.theme.linkColor}")
        };

      init{
         children= [ textImgHBox, statusButton, line, statusList ]
      }
}