package motoSample;

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.bean.ManagedProperty;
import javax.faces.context.FacesContext;
import javax.faces.context.ExternalContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import java.util.logging.Logger;
import javax.inject.Inject;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.PreparedStatement;


import java.util.ArrayList;
import javax.faces.model.SelectItem;
import javax.faces.event.ValueChangeEvent;
import javax.annotation.PostConstruct;
import javax.faces.component.html.HtmlCommandLink;

import java.util.Date;
import java.text.SimpleDateFormat;

import org.atmosphere.cpr.Broadcaster;
import org.atmosphere.cpr.BroadcasterFactory;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;


@ManagedBean
@ViewScoped
public class ChatBean implements Serializable {

    @Inject
    private Logger log;


    @Inject
    private FacesContext context;


    //inject user bean
    @ManagedProperty("#{userBean}")
    private UserBean userBean;
    //all login members list
    @ManagedProperty("#{loginMemberBean}")
    private LoginMemberBean loginMemberBean;
    
    private String msg;
    private String chatRoom;
    private int oldestChatId;
    private ArrayList<ChatMessage> msgList;

    //members that are associated with this chat room
    private MemberList memList;
    
    public final static int LIST_LOAD_SIZE = 10;

    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getMsg() {
        return "";
    }

    public void setChatRoom(String chatRoom) {
        this.chatRoom = chatRoom;
    }
    public String getChatRoom() {
        return chatRoom;
    }
	public MemberList getMemList(){
		return memList;
	}
    

    //session bean injection. setter only.
    public void setUserBean(UserBean userBean) {
        this.userBean = userBean;
    }
    public void setLoginMemberBean(LoginMemberBean loginMemberBean) {
        this.loginMemberBean = loginMemberBean;
    }

    ///chat list data
    public static class ChatMessage {
        private String uname;
        private String msg;
        private String date;
        public String getUname() {
            return uname;
        }
        public String getMsg() {
            return msg;
        }
        public String getDate() {
            return date;
        }
        public void setUname(String uname) {
            this.uname = uname;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
        public void setDate(String date) {
            this.date = date;
        }
    }

	private void initMsgList(){
        log.info("initMsgList: " + chatRoom);
        try {
            Connection conn = Resources.getConnection();
            String uid = userBean.getUid();
            String sqlString = "select user_id, message, msg_date, msg_id from tb_chat_msg where chat_room=\'" + chatRoom +"\' order by msg_id desc";

            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery(sqlString);
            
            if (msgList == null) {
                msgList = new ArrayList<ChatMessage>();
            }
            else {
                msgList.clear();
            }
            int load_cnt = 0;
            while (rs.next()) {
                ChatMessage m = new ChatMessage();
                m.uname = rs.getString("user_id");
                m.msg = rs.getString("message");
                m.date = rs.getString("msg_date");
                oldestChatId = rs.getInt("msg_id");
                msgList.add(0, m);
                if (++load_cnt == LIST_LOAD_SIZE)
                    break;
            }
            log.info("oldestChatId: " + oldestChatId);
            
            rs.close();
            conn.close();
        }
        catch (SQLException se) {
            log.severe("sql err!!!");
        }
	}

    public ArrayList<ChatMessage> getMsgList(){
		return msgList;
	}

    public static String formatDate() {
        Date d = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        return df.format(d);
    }
    
    public void doPost() {
        //skip empty message....
        if (msg.equals(""))
            return;
        
        String dt = formatDate();
        try {
            Connection conn = Resources.getConnection();
            String sqlString = "insert into tb_chat_msg (user_id , chat_room , message , msg_date, deleted) values (?, ?, ?, ?, ?)";
            //log.info("sql = " + sqlString);
            
            PreparedStatement ps= conn.prepareStatement(sqlString); 
            ps.setString(1, userBean.getUid());
            ps.setString(2, chatRoom);
            ps.setString(3, msg);
            ps.setString(4, dt);
            ps.setString(5, "false");

            int cnt = ps.executeUpdate();
            log.info(cnt + " records inserted");

            conn.close();

            //in order to update the display, notify the message to the other chat users (including myself.).
            PushMsg pm = PushMsg.newChatMessage();
            ChatMessage cm = pm.getChatMessage();
            cm.setMsg(msg);
    	    cm.setDate(dt);
    	    cm.setUname(userBean.getUid());

            String br_url = "/comet/" + chatRoom;
            Broadcaster b = BroadcasterFactory.getDefault().lookup(br_url, true);
            ObjectMapper mapper = new ObjectMapper();
            try {
                String json = mapper.writeValueAsString(pm);
                b.broadcast(json);
                log.info("broadcasted: " + br_url);
            } catch (IOException e) {
                log.severe("json encode error.");
            }
        }
        catch (SQLException se) {
            log.severe("sql err!!!");
        }
    }

    public void loadOldMsg() {
        //log.info("loadOldMsg oldestChatId: " + oldestChatId);
        try {
            Connection conn = Resources.getConnection();
            String uid = userBean.getUid();
            String sqlString = "select user_id, message, msg_date, msg_id from tb_chat_msg where chat_room=\'" 
                                + chatRoom +"\' and msg_id < " + oldestChatId + " order by msg_id desc";

            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery(sqlString);
            
            int load_cnt = 0;
            ArrayList<ChatMessage> retList = new ArrayList<ChatMessage>();
            while (rs.next()) {
                ChatMessage m = new ChatMessage();
                m.uname = rs.getString("user_id");
                m.msg = rs.getString("message");
                m.date = rs.getString("msg_date");
                oldestChatId = rs.getInt("msg_id");
                retList.add(m);
                if (++load_cnt == LIST_LOAD_SIZE)
                    break;
            }
            log.info("oldestChatId: " + oldestChatId);
            
            rs.close();
            conn.close();

            ExternalContext externalContext = context.getExternalContext();
            externalContext.setResponseContentType("application/json");
            externalContext.setResponseCharacterEncoding("UTF-8");
            if (load_cnt == 0) {
                log.info("no more old msg...");
            }
            else {
                //output json object.
                ObjectMapper mapper = new ObjectMapper();
                String json = mapper.writeValueAsString(retList);
                externalContext.getResponseOutputWriter().write(json);
            }
            context.responseComplete();
        }
        catch (SQLException se) {
            log.severe("sql err!!!");
        }
        catch (IOException ioe) {
            log.severe("io err!!!");
        }
        
    }
    
    void initMembers() {
        if (memList == null)
            memList = new MemberList();
        memList.setChatRoom(chatRoom);
        memList.setLoginMember(loginMemberBean);
        memList.initMemList();
    }
    ///chat room menu value changed listener
    public void chatRoomChanged(ValueChangeEvent e) {
        //chat room is changed. initialize the msg list.
        chatRoom = e.getNewValue().toString();
        log.info("chat room changed: " + this.chatRoom);
        initMsgList();
        initMembers();
    }

    @PostConstruct
    public void postInit() {
        ArrayList<SelectItem> flights = userBean.getFlights();
        if (flights != null) {
            chatRoom = flights.get(0).getValue().toString();

            //log.info("method: " + ((HttpServletRequest) context.getExternalContext().getRequest()).getMethod());
            if (((HttpServletRequest) context.getExternalContext().getRequest()).getMethod().equals("GET")) {
                log.info("get access. init chat list");
                //in get access, the chat room is not selected..
                initMsgList();
                initMembers();
            }
        }
    }

}
