/*
    Message builder for communicating over the websocket
 */
(function(context, $) {

    "use strict";

    context.JK = context.JK || {};

    var msg = context.JK.MessageType = {
        LOGIN                     : "LOGIN",
        LOGIN_ACK                 : "LOGIN_ACK",
        LOGIN_MUSIC_SESSION       : "LOGIN_MUSIC_SESSION",
        LOGIN_MUSIC_SESSION_ACK   : "LOGIN_MUSIC_SESSION_ACK",
        LEAVE_MUSIC_SESSION       : "LEAVE_MUSIC_SESSION",
        LEAVE_MUSIC_SESSION_ACK   : "LEAVE_MUSIC_SESSION_ACK",
        HEARTBEAT                 : "HEARTBEAT",
        HEARTBEAT_ACK             : "HEARTBEAT_ACK",
        SUBSCRIBE                 : "SUBSCRIBE",
        UNSUBSCRIBE               : "UNSUBSCRIBE",
        SUBSCRIPTION_MESSAGE      : "SUBSCRIPTION_MESSAGE",
        SUBSCRIBE_BULK            : "SUBSCRIBE_BULK",
        USER_STATUS               : "USER_STATUS",

        // friend notifications
        FRIEND_UPDATE             : "FRIEND_UPDATE",
        FRIEND_REQUEST            : "FRIEND_REQUEST",
        FRIEND_REQUEST_ACCEPTED   : "FRIEND_REQUEST_ACCEPTED",
        FRIEND_SESSION_JOIN       : "FRIEND_SESSION_JOIN",
        NEW_USER_FOLLOWER         : "NEW_USER_FOLLOWER",
        NEW_BAND_FOLLOWER         : "NEW_BAND_FOLLOWER",

        // session notifications
        SESSION_INVITATION        : "SESSION_INVITATION",
        SESSION_ENDED             : "SESSION_ENDED",
        JOIN_REQUEST              : "JOIN_REQUEST",
        JOIN_REQUEST_APPROVED     : "JOIN_REQUEST_APPROVED",
        JOIN_REQUEST_REJECTED     : "JOIN_REQUEST_REJECTED",
        SESSION_JOIN              : "SESSION_JOIN",
        SESSION_DEPART            : "SESSION_DEPART",
        TRACKS_CHANGED            : "TRACKS_CHANGED",
        MUSICIAN_SESSION_JOIN     : "MUSICIAN_SESSION_JOIN",
        BAND_SESSION_JOIN         : "BAND_SESSION_JOIN",
        SCHEDULED_SESSION_INVITATION            : "SCHEDULED_SESSION_INVITATION",
        SCHEDULED_SESSION_RSVP                  : "SCHEDULED_SESSION_RSVP",
        SCHEDULED_SESSION_RSVP_APPROVED         : "SCHEDULED_SESSION_RSVP_APPROVED",
        SCHEDULED_SESSION_RSVP_CANCELLED        : "SCHEDULED_SESSION_RSVP_CANCELLED",
        SCHEDULED_SESSION_RSVP_CANCELLED_ORG    : "SCHEDULED_SESSION_RSVP_CANCELLED_ORG",
        SCHEDULED_SESSION_CANCELLED             : "SCHEDULED_SESSION_CANCELLED",
        SCHEDULED_SESSION_RESCHEDULED           : "SCHEDULED_SESSION_RESCHEDULED",
        SCHEDULED_SESSION_REMINDER              : "SCHEDULED_SESSION_REMINDER",
        SCHEDULED_SESSION_COMMENT               : "SCHEDULED_SESSION_COMMENT",

        SCHEDULED_JAMCLASS_INVITATION           : "SCHEDULED_JAMCLASS_INVITATION",
        LESSON_MESSAGE                          : "LESSON_MESSAGE",

        // recording notifications
        MUSICIAN_RECORDING_SAVED  : "MUSICIAN_RECORDING_SAVED",
        BAND_RECORDING_SAVED      : "BAND_RECORDING_SAVED",
        RECORDING_STARTED         : "RECORDING_STARTED",
        RECORDING_ENDED           : "RECORDING_ENDED",
        RECORDING_MASTER_MIX_COMPLETE  : "RECORDING_MASTER_MIX_COMPLETE",
        DOWNLOAD_AVAILABLE        : "DOWNLOAD_AVAILABLE",
        RECORDING_STREAM_MIX_COMPLETE  : "RECORDING_STREAM_MIX_COMPLETE",

        // band notifications
        BAND_INVITATION           : "BAND_INVITATION",
        BAND_INVITATION_ACCEPTED  : "BAND_INVITATION_ACCEPTED",

        // text message
        TEXT_MESSAGE              : "TEXT_MESSAGE",
        CHAT_MESSAGE              : "CHAT_MESSAGE",
        SEND_CHAT_MESSAGE         : "SEND_CHAT_MESSAGE",

        // broadcast notifications
        SOURCE_UP_REQUESTED       : "SOURCE_UP_REQUESTED",
        SOURCE_DOWN_REQUESTED     : "SOURCE_DOWN_REQUESTED",
        SOURCE_UP                 : "SOURCE_UP",
        SOURCE_DOWN               : "SOURCE_DOWN",

        TEST_SESSION_MESSAGE      : "TEST_SESSION_MESSAGE",
        PING_REQUEST              : "PING_REQUEST",
        PING_ACK                  : "PING_ACK",
        PEER_MESSAGE              : "PEER_MESSAGE",
        CLIENT_UPDATE             : "CLIENT_UPDATE",
        GENERIC_MESSAGE           : "GENERIC_MESSAGE",
        RELOAD                    : "RELOAD",
        RESTART_APPLICATION       : "RESTART_APPLICATION",
        STOP_APPLICATION          : "STOP_APPLICATION",
        SERVER_BAD_STATE_RECOVERED: "SERVER_BAD_STATE_RECOVERED",
        SERVER_GENERIC_ERROR      : "SERVER_GENERIC_ERROR",
        SERVER_REJECTION_ERROR    : "SERVER_REJECTION_ERROR",
        SERVER_BAD_STATE_ERROR    : "SERVER_BAD_STATE_ERROR",
        SERVER_DUPLICATE_CLIENT_ERROR : "SERVER_DUPLICATE_CLIENT_ERROR"
    };

    var route_to = context.JK.RouteToPrefix = {
        CLIENT   : "client",
        SESSION  : "session",
        SERVER   : "server",
        USER     : "user"
    };

    var factory = {};

    function client_container(type, target, inner) {
        var type_field = type.toLowerCase();
        var body = { "type" : type, "route_to" : target};
        body[type_field] = inner;
        return body;
    }

    function route_to_client(client_id) {
        return route_to.CLIENT + ":" + client_id;
    }

    function route_to_session(session_id) {
        return route_to.SESSION + ":" + session_id;
    }

    // ping the provided client_id
    factory.ping = function(client_id) {
        var data = {};
        return client_container(msg.PING_REQUEST, route_to_client(client_id), data);
    };

    // Heartbeat message
    factory.heartbeat = function(lastNotificationSeen, lastNotificationSeenAt, active) {
        var data = {};
        data.notification_seen = lastNotificationSeen;
        data.notification_seen_at = lastNotificationSeenAt;
        data.active = active;
        return client_container(msg.HEARTBEAT, route_to.SERVER, data);
    };

    // User Status update message
    factory.userStatus = function(active, status) {
        var data = {};
        data.active = active;
        data.status = status;
        return client_container(msg.USER_STATUS, route_to.SERVER, data);
    };

    factory.chatMessage = function(channel, msg) {
        var data = {}
        data.channel = {}
        data.msg = {}

        return client_container(msg.SEND_CHAT_MESSAGE, route_to.SERVER, data)
    }

    // create a login message using user/pass
    factory.login_with_user_pass = function(username, password) {
        var login = { username : username , password : password };
        return client_container(msg.LOGIN, route_to.SERVER, login);
    };

    // create a login message using token (a cookie or similiar)
    // reconnect_music_session_id is an optional argument that allows the session to be immediately associated
    // with a music session.
    factory.login_with_token = function(token, reconnect_music_session_id, client_type) {
    //context.JK.logger.debug("*** login_with_token: client_id = "+$.cookie("client_id"));
        var login = {
          token : token,
          client_id : $.cookie("client_id"),
          client_type : client_type
            };
        return client_container(msg.LOGIN, route_to.SERVER, login);
    };

    factory.logout = function() {
        var logout = {}
        return client_container(msg.LOGOUT, route_to.SERVER, logout);
    }

    // create a login message using only the client_id.  only valid for latency_tester
    factory.login_with_client_id = function(client_id, client_type) {
      if(client_type != 'latency_tester') {
        throw "client_type must be latency_tester in login_with_client_id";
      }
      var login = {
        client_id : client_id,
        client_type : client_type
      };
      return client_container(msg.LOGIN, route_to.SERVER, login);
    };

    // create a music session login message
    factory.login_music_session = function(music_session) {
        var login_music_session = { music_session : music_session };
        return client_container(msg.LOGIN_MUSIC_SESSION, route_to.SERVER, login_music_session);
    };

    // client-to-client message
    factory.client_p2p_message = function(sender_client_id, receiver_client_id, message) {
        var peer_message = { "message" : message };
        var result = client_container(msg.PEER_MESSAGE, route_to_client(receiver_client_id), peer_message);
        result.from = sender_client_id;
        return result;
    };

    factory.subscribe = function(type, id) {
        var subscribe_msg = {type: type, id: id}
        return client_container(msg.SUBSCRIBE, route_to.SERVER, subscribe_msg);
    }

    factory.subscribeBulk = function(types, ids) {
        var subscribe_bulk_msg = {types: types, ids: ids}
        return client_container(msg.SUBSCRIBE_BULK, route_to.SERVER, subscribe_bulk_msg);
    }

    factory.unsubscribe = function(type, id) {
        var unsubscribe_msg = {type: type, id: id}
        return client_container(msg.UNSUBSCRIBE, route_to.SERVER, unsubscribe_msg);
    }

    context.JK.MessageFactory = factory;

})(window, jQuery);