/****************************************************************
 * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
 * =============================================================
 * License Information: http://lamsfoundation.org/licensing/lams/2.0/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2.0 
 * as published by the Free Software Foundation.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 * 
 * http://www.gnu.org/licenses/gpl.txt
 * ****************************************************************
 */

/* $$Id: TwitterServicePOJO.java,v 1.45 2009/07/26 22:18:27 marcin Exp $$ */
package org.lamsfoundation.lams.tool.twitter.service;

import java.io.InputStream;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.log4j.Logger;
import org.lamsfoundation.lams.contentrepository.ItemNotFoundException;
import org.lamsfoundation.lams.contentrepository.NodeKey;
import org.lamsfoundation.lams.contentrepository.RepositoryCheckedException;
import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler;
import org.lamsfoundation.lams.learning.service.ILearnerService;
import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException;
import org.lamsfoundation.lams.learningdesign.service.IExportToolContentService;
import org.lamsfoundation.lams.learningdesign.service.ImportToolContentException;
import org.lamsfoundation.lams.notebook.model.NotebookEntry;
import org.lamsfoundation.lams.notebook.service.ICoreNotebookService;
import org.lamsfoundation.lams.tool.ToolContentImport102Manager;
import org.lamsfoundation.lams.tool.ToolContentManager;
import org.lamsfoundation.lams.tool.ToolOutput;
import org.lamsfoundation.lams.tool.ToolOutputDefinition;
import org.lamsfoundation.lams.tool.ToolSessionExportOutputData;
import org.lamsfoundation.lams.tool.ToolSessionManager;
import org.lamsfoundation.lams.tool.exception.DataMissingException;
import org.lamsfoundation.lams.tool.exception.SessionDataExistsException;
import org.lamsfoundation.lams.tool.exception.ToolException;
import org.lamsfoundation.lams.tool.twitter.TwitterApplicationException;
import org.lamsfoundation.lams.tool.twitter.TwitterAttachment;
import org.lamsfoundation.lams.tool.twitter.TwitterConstants;
import org.lamsfoundation.lams.tool.twitter.TwitterContent;
import org.lamsfoundation.lams.tool.twitter.TwitterSession;
import org.lamsfoundation.lams.tool.twitter.TwitterUser;
import org.lamsfoundation.lams.tool.twitter.TwitterUserTweet;
import org.lamsfoundation.lams.tool.twitter.dao.ITwitterAttachmentDAO;
import org.lamsfoundation.lams.tool.twitter.dao.ITwitterContentDAO;
import org.lamsfoundation.lams.tool.twitter.dao.ITwitterSessionDAO;
import org.lamsfoundation.lams.tool.twitter.dao.ITwitterUserDAO;
import org.lamsfoundation.lams.tool.twitter.dao.ITwitterUserTweetDAO;
import org.lamsfoundation.lams.tool.service.ILamsToolService;
import org.lamsfoundation.lams.usermanagement.dto.UserDTO;
import org.lamsfoundation.lams.util.WebUtil;
import org.springframework.dao.DataAccessException;

/**
 * An implementation of the TwitterService interface.
 * 
 * As a requirement, all LAMS tool's service bean must implement ToolContentManager and ToolSessionManager.
 * 
 * @author mtruong
 * 
 */
public class TwitterServicePOJO implements ITwitterService, ToolContentManager, ToolSessionManager,
	ToolContentImport102Manager {

    private TwitterContent twitterContent;
    private ITwitterContentDAO twitterContentDAO = null;

    private TwitterSession twitterSession;
    private ITwitterSessionDAO twitterSessionDAO = null;

    private ILearnerService learnerService;
    private ILamsToolService toolService;

    private TwitterUser twitterUser;
    private ITwitterUserDAO twitterUserDAO = null;
    
    private TwitterUserTweet[] twitterUserTweets;
    private ITwitterUserTweetDAO twitterUserTweetDAO = null;

    private ITwitterAttachmentDAO twitterAttachmentDAO = null;
    private IToolContentHandler twitterToolContentHandler = null;

    private IExportToolContentService exportContentService;
    private static Logger log = Logger.getLogger(TwitterServicePOJO.class);

    private ICoreNotebookService coreNotebookService;

    /*
     * ============================================================================== Methods for access to
     * TwitterContent objects ==============================================================================
     */

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitter(Long)
     */
    public TwitterContent retrieveTwitter(Long twitterContentId) throws TwitterApplicationException {
	if (twitterContentId == null) {
	    String error = "Unable to continue. The tool content id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterContent = twitterContentDAO.findTwitterContentById(twitterContentId);

	} catch (DataAccessException e) {
	    throw new TwitterApplicationException("An exception has occured when trying to retrieve twitter content: "
		    + e.getMessage(), e);
	}

	return twitterContent;
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitterBySessionID(Long)
     */
    public TwitterContent retrieveTwitterBySessionID(Long twitterSessionId) {
	if (twitterSessionId == null) {
	    String error = "Unable to continue. The tool session id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterContent = twitterContentDAO.getTwitterContentBySession(twitterSessionId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException("An exception has occured when trying to retrieve twitter content: "
		    + e.getMessage(), e);
	}

	return twitterContent;
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#saveTwitter(org.lamsfoundation.lams.tool.twitter.TwitterContent)
     */
    public void saveTwitter(TwitterContent twitterContent) {
	try {
	    if (twitterContent.getUid() == null) {
		twitterContentDAO.saveTwitterContent(twitterContent);
	    } else {
		twitterContentDAO.updateTwitterContent(twitterContent);
	    }
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to save the twitter content object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeTwitterSessions(org.lamsfoundation.lams.tool.twitter.TwitterContent)
     */
    public void removeTwitterSessionsFromContent(TwitterContent twitterContent) {
	try {
	    twitterContent.getTwitterSessions().clear();
	    // updateTwitter(twitterContent);

	    twitterContentDAO.removeTwitterSessions(twitterContent);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove the sessions associated with this twitter content object: "
			    + e.getMessage(), e);
	}

    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeTwitter(org.lamsfoundation.lams.tool.twitter.TwitterContent)
     */
    public void removeTwitter(Long twitterContentId) {
	if (twitterContentId == null) {
	    String error = "Unable to continue. The tool content id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterContentDAO.removeTwitter(twitterContentId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove this twitter content object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeTwitter(org.lamsfoundation.lams.tool.twitter.TwitterContent)
     */
    public void removeTwitter(TwitterContent twitterContent) {
	try {
	    twitterContentDAO.removeTwitter(twitterContent);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove this twitter content object: "
			    + e.getMessage(), e);
	}
    }

    /*
     * ============================================================================== Methods for access to
     * TwitterSession objects ==============================================================================
     */

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitterSession(Long)
     */
    public TwitterSession retrieveTwitterSession(Long twitterSessionId) {
	if (twitterSessionId == null) {
	    String error = "Unable to continue. The tool session id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterSession = twitterSessionDAO.findTwitterSessionById(twitterSessionId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "An exception has occured when trying to retrieve twitter session object: " + e.getMessage(), e);
	}

	return twitterSession;
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#saveTwitterSession(org.lamsfoundation.lams.tool.twitter.TwitterSession)
     */
    public void saveTwitterSession(TwitterSession twitterSession) {
	try {
	    TwitterContent content = twitterSession.getTwitterContent();
	    // content.getTwitterSessions().add(twitterSession);
	    // content.

	    /* updateTwitter(content); */
	    twitterSessionDAO.saveTwitterSession(twitterSession);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to save this twitter session: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#updateTwitterSession(org.lamsfoundation.lams.tool.twitter.TwitterSession)
     */
    public void updateTwitterSession(TwitterSession twitterSession) {
	try {
	    twitterSessionDAO.updateTwitterSession(twitterSession);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to update this twitter session: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeSession(Long)
     */
    public void removeSession(Long twitterSessionId) {
	if (twitterSessionId == null) {
	    String error = "Unable to continue. The tool session id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    TwitterSession sessionToDelete = retrieveTwitterSession(twitterSessionId);
	    TwitterContent contentReferredBySession = sessionToDelete.getTwitterContent();
	    // un-associate the session from content
	    contentReferredBySession.getTwitterSessions().remove(sessionToDelete);
	    twitterSessionDAO.removeTwitterSession(twitterSessionId);
	    // updateTwitter(contentReferredBySession);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove this twitter session object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeSession(org.lamsfoundation.lams.tool.twitter.TwitterSession)
     */
    public void removeSession(TwitterSession twitterSession) {
	try {
	    TwitterContent contentReferredBySession = twitterSession.getTwitterContent();
	    // un-associate the session from content
	    contentReferredBySession.getTwitterSessions().remove(twitterSession);

	    twitterSessionDAO.removeTwitterSession(twitterSession);
	    // updateTwitter(contentReferredBySession);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove this twitter session object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeTwitterUsersFromSession(org.lamsfoundation.lams.tool.twitter.TwitterSession)
     */
    public void removeTwitterUsersFromSession(TwitterSession twitterSession) {
	try {
	    twitterSession.getTwitterUsers().clear();
	    // updateTwitterSession(twitterSession);

	    twitterSessionDAO.removeTwitterUsers(twitterSession);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove the users associated with this twitter session instance: "
			    + e.getMessage(), e);
	}

    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitterSessionByUserID(java.lang.Long)
     */
    public TwitterSession retrieveTwitterSessionByUserID(Long userId) {
	if (userId == null) {
	    String error = "Unable to continue. The tool session id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterSession = twitterSessionDAO.getTwitterSessionByUser(userId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to retrieve twitter session instance "
			    + e.getMessage(), e);
	}
	return twitterSession;

    }

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#getSessionIdsFromContent(org.lamsfoundation.lams.tool.twitter.TwitterContent) */
    public List getSessionIdsFromContent(TwitterContent content) {
	List list = null;
	try {
	    list = twitterSessionDAO.getSessionsFromContent(content);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to the list of session ids from content "
			    + e.getMessage(), e);
	}
	return list;
    }

    /*
     * ============================================================================== Methods for access to
     * TwitterUser objects ==============================================================================
     */

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitterUser(java.lang.Long)
     */
    public TwitterUser retrieveTwitterUser(Long twitterUserId, Long twitterSessionId) {
	if (twitterUserId == null) {
	    String error = "Unable to continue. The user id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterUser = twitterUserDAO.getTwitterUser(twitterUserId, twitterSessionId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException("An exception has occured when trying to retrieve twitter user: "
		    + e.getMessage(), e);
	}

	return twitterUser;
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#saveTwitterUser(org.lamsfoundation.lams.tool.twitter.TwitterUser)
     */
    public void saveTwitterUser(TwitterUser twitterUser) {
	try {
	    TwitterSession session = twitterUser.getTwitterSession();
	    session.getTwitterUsers().add(twitterUser);
	    // updateTwitterSession(session);

	    twitterUserDAO.saveTwitterUser(twitterUser);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to save the twitter user object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitterUserBySession(java.lang.Long,
     * java.lang.Long)
     */
    public TwitterUser retrieveTwitterUserBySession(Long userId, Long sessionId) {
	try {
	    twitterUser = twitterUserDAO.getTwitterUserBySession(userId, sessionId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to retrive the twitter user object: "
			    + e.getMessage(), e);
	}

	return twitterUser;
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#updateTwitterUser(org.lamsfoundation.lams.tool.twitter.TwitterUser)
     */
    public void updateTwitterUser(TwitterUser twitterUser) {
	try {
	    twitterUserDAO.updateTwitterUser(twitterUser);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to update the twitter user object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeUser(org.lamsfoundation.lams.tool.twitter.TwitterUser)
     */
    public void removeUser(TwitterUser twitterUser) {
	try {
	    TwitterSession session = twitterUser.getTwitterSession();
	    session.getTwitterUsers().remove(twitterUser);

	    twitterUserDAO.removeTwitterUser(twitterUser);

	    // updateTwitterSession(session);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove the twitter user object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeUser(java.lang.Long)
     */
    public void removeUser(Long twitterUserId, Long toolSessionId) {
	if (twitterUserId == null) {
	    String error = "Unable to continue. The user id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}
	try {
	    TwitterUser user = retrieveTwitterUser(twitterUserId, toolSessionId);
	    TwitterSession session = user.getTwitterSession();
	    session.getTwitterUsers().remove(user);
	    twitterUserDAO.removeTwitterUser(twitterUserId);

	    // updateTwitterSession(session);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove the twitter user object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#addSession(java.lang.Long,
     *      org.lamsfoundation.lams.tool.twitter.TwitterSession)
     */
    public void addSession(Long twitterContentId, TwitterSession session) {

	if (twitterContentId == null || session == null) {
	    String error = "Unable to continue. The tool content id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterContentDAO.addTwitterSession(twitterContentId, session);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException("EXCEPTION: An exception has occurred while trying to create session: "
		    + e.getMessage(), e);
	}
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#addUser(java.lang.Long,
     *      org.lamsfoundation.lams.tool.twitter.TwitterSession)
     */
    public void addUser(Long twitterSessionId, TwitterUser user) {

	if (twitterSessionId == null) {
	    String error = "Unable to continue. The tool session id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}
	try {
	    twitterSessionDAO.addTwitterUsers(twitterSessionId, user);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException("EXCEPTION: An exception has occurred while trying to create user: "
		    + e.getMessage(), e);
	}
    }

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#getNumberOfUsersInSession(org.lamsfoundation.lams.tool.twitter.oticeboardSession) */
    public int getNumberOfUsersInSession(TwitterSession session) {
	int numberOfUsers;
	try {
	    numberOfUsers = twitterUserDAO.getNumberOfUsers(session);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to get the number of users in the session: "
			    + e.getMessage(), e);
	}
	return numberOfUsers;
    }

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#calculateTotalNumberOfUsers(java.lang.Long) */
    public int calculateTotalNumberOfUsers(Long toolContentId) {

	if (toolContentId == null) {
	    String error = "Unable to continue. The tool content id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	int totalNumberOfUsers = 0;
	try {
	    twitterContent = retrieveTwitter(toolContentId);
	    List listOfSessionIds = getSessionIdsFromContent(twitterContent);

	    Iterator i = listOfSessionIds.iterator();

	    while (i.hasNext()) {
		Long sessionId = (Long) i.next();
		int usersInThisSession = getNumberOfUsersInSession(retrieveTwitterSession(sessionId));
		totalNumberOfUsers = totalNumberOfUsers + usersInThisSession;
	    }
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while calculating the total number of users in tool activity "
			    + e.getMessage(), e);
	}
	return totalNumberOfUsers;
    }

    public List getUsersBySession(Long sessionId) {

	if (sessionId != null) {
	    try {
		return twitterUserDAO.getTwitterUsersBySession(sessionId);
	    } catch (DataAccessException e) {
		throw new TwitterApplicationException(
			"EXCEPTION: An exception has occurred while trying to get the list of users in the session: "
				+ e.getMessage(), e);
	    }
	} else {
	    TwitterServicePOJO.log.error("Unable to continue. Session id is missing");
	}
	return null;
    }
    
    /*
     * ============================================================================== Methods for access to
     * TwitterUserTweet objects ==============================================================================
     */

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveNumberOfTweetsByUser(java lang.Long, java.lang.Long)
     */
    public int retrieveNumberOfTweetsByUser(Long toolContentId, Long userId){
	if (toolContentId == null){
	    String error = "Unable to continue. The content id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}
	if (userId == null){
	    String error = "Unable to continue. The user id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}
	
	int numberOfTweets = 0;
	
	try {
	    numberOfTweets = twitterUserTweetDAO.getNumberOfTweetsByUser(toolContentId, userId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException("An exception has occured when trying to retrieve twitter tweets: "
		    + e.getMessage(), e);
	}

	return numberOfTweets;
    }
    
    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitterUserTweet(java.lang.Long)
     */
    public TwitterUserTweet[] retrieveTwitterUserTweet(Long toolContentId){
	if (toolContentId == null) {
	    String error = "Unable to continue. The content id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    twitterUserTweets = twitterUserTweetDAO.getTwitterUserTweet(toolContentId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException("An exception has occured when trying to retrieve twitter tweets: "
		    + e.getMessage(), e);
	}

	return twitterUserTweets;
    }

    /**
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#saveTwitterUserTweet(org.lamsfoundation.lams.tool.twitter.TwitterUserTweet)
     */
    public void saveTwitterUserTweet(TwitterUserTweet twitterUserTweet) {
	try {

	    twitterUserTweetDAO.saveTwitterUserTweet(twitterUserTweet);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to save the twitter user tweet object: "
			    + e.getMessage(), e);
	}
    }

    /**
     * org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveTwitterUserTweetByUser(java.lang.Long,
     * java.lang.Long)
     */
    public TwitterUserTweet[] retrieveTwitterUserTweetByUser(Long userId, Long toolContentId) {
	try {
	    twitterUserTweets = twitterUserTweetDAO.getTwitterUserTweetByUser(userId, toolContentId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to retrive the twitter user tweet object: "
			    + e.getMessage(), e);
	}

	return twitterUserTweets;
    }

    /*
     * ============================================================================== Methods for access to
     * TwitterUser objects ==============================================================================
     */

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveAttachment(java.lang.Long) */
    public TwitterAttachment retrieveAttachment(Long attachmentId) {
	if (attachmentId == null) {
	    String error = "Unable to continue. The attachment id is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}

	try {
	    return twitterAttachmentDAO.retrieveAttachment(attachmentId);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to retrieve the attachment " + e.getMessage(), e);
	}
    }

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveAttachmentByUuid(java.lang.Long) */
    public TwitterAttachment retrieveAttachmentByUuid(Long uuid) {
	if (uuid == null) {
	    String error = "Unable to continue. The uuid is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}
	try {
	    return twitterAttachmentDAO.retrieveAttachmentByUuid(uuid);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to retrieve the attachment " + e.getMessage(), e);
	}
    }

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#retrieveAttachment(java.lang.String) */
    public TwitterAttachment retrieveAttachmentByFilename(String filename) {
	if (filename == null || filename.trim().length() == 0) {
	    String error = "Unable to continue. The filename is missing";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}
	try {
	    return twitterAttachmentDAO.retrieveAttachmentByFilename(filename);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to retrieve the attachment with filename "
			    + filename + " " + e.getMessage(), e);
	}
    }

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#getAttachmentIdsFromContent(org.lamsfoundation.lams.tool.twitter.TwitterContent) */
    public List getAttachmentIdsFromContent(TwitterContent twitterContent) {
	try {
	    return twitterAttachmentDAO.getAttachmentIdsFromContent(twitterContent);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to retrieve the list of attachment ids "
			    + e.getMessage(), e);
	}
    }

    /** @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#saveAttachment(org.lamsfoundation.lams.tool.twitter.TwitterAttachment) */
    public void saveAttachment(TwitterContent content, TwitterAttachment attachment) {
	try {
	    content.getTwitterAttachments().add(attachment);
	    attachment.setTwitterContent(content);
	    saveTwitter(content);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to save the attachment " + e.getMessage(), e);
	}
    }

    /**
     * @throws RepositoryCheckedException
     * @throws
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#removeAttachment(org.lamsfoundation.lams.tool.twitter.TwitterAttachment)
     */
    public void removeAttachment(TwitterContent content, TwitterAttachment attachment)
	    throws RepositoryCheckedException {
	try {
	    attachment.setTwitterContent(null);
	    content.getTwitterAttachments().remove(attachment);
	    saveTwitter(content);
	} catch (DataAccessException e) {
	    throw new TwitterApplicationException(
		    "EXCEPTION: An exception has occurred while trying to remove this attachment" + e.getMessage(), e);
	}
    }

    /**
     * @throws RepositoryCheckedException
     * @see org.lamsfoundation.lams.tool.twitter.service.ITwitterService#uploadFile(java.io.InputStream,
     *      java.lang.String, java.lang.String, java.lang.String)
     */
    public NodeKey uploadFile(InputStream istream, String filename, String contentType, String fileType)
	    throws RepositoryCheckedException {
	return twitterToolContentHandler.uploadFile(istream, filename, contentType, fileType);
    }

    /* ===============Methods implemented from ToolContentManager =============== */

    /** @see org.lamsfoundation.lams.tool.ToolContentManager#copyToolContent(java.lang.Long, java.lang.Long) */
    public void copyToolContent(Long fromContentId, Long toContentId) throws ToolException {

	if (toContentId == null) {
	    throw new ToolException("Failed to copy Twitter tool content. Missing parameter: toContentId");
	}
	if (fromContentId == null) {
	    // use the default content Id
	    // fromContentId = TwitterConstants.DEFAULT_CONTENT_ID;
	    fromContentId = getToolDefaultContentIdBySignature(TwitterConstants.TOOL_SIGNATURE);
	}

	// fromContentId might not have any content, in this case use default content
	// default content id might not have any contnet, throw exception
	TwitterContent originalTwitter = null;

	try {
	    if ((originalTwitter = retrieveTwitter(fromContentId)) == null) // the id given does not have content, use
	    // default content
	    {
		// use default content id to grab contents
		TwitterContent defaultContent = retrieveTwitter(getToolDefaultContentIdBySignature(TwitterConstants.TOOL_SIGNATURE));

		if (defaultContent != null) {
		    TwitterContent newContent = TwitterContent.newInstance(defaultContent, toContentId,
			    twitterToolContentHandler);
		    saveTwitter(newContent);
		} else {
		    throw new ToolException("Default content is missing. Unable to copy tool content");
		}
	    } else {
		TwitterContent newTwitterContent = TwitterContent.newInstance(originalTwitter, toContentId,
			twitterToolContentHandler);
		saveTwitter(newTwitterContent);
	    }
	} catch (RepositoryCheckedException e) {
	    TwitterServicePOJO.log
		    .error("Unable to copy the tool content due to a content repository error. fromContentId "
			    + fromContentId + " toContentId " + toContentId);
	    throw new ToolException(e);
	}

    }

    /** @see org.lamsfoundation.lams.tool.ToolContentManager#setAsDefineLater(java.lang.Long) */
    public void setAsDefineLater(Long toolContentId, boolean value) throws DataMissingException, ToolException {
	TwitterContent twitterContent = getAndCheckIDandObject(toolContentId);

	twitterContent.setDefineLater(value);
	// twitterContent.setContentInUse(false); //if define later is set to true, then contentInUse flag should be false
	saveTwitter(twitterContent);

    }

    /** @see org.lamsfoundation.lams.tool.ToolContentManager#setAsRunOffline(java.lang.Long) */
    public void setAsRunOffline(Long toolContentId, boolean value) throws DataMissingException, ToolException {
	TwitterContent twitterContent = getAndCheckIDandObject(toolContentId);

	twitterContent.setForceOffline(value);
	saveTwitter(twitterContent);
    }

    /** @see org.lamsfoundation.lams.tool.ToolContentManager#removeToolContent(java.lang.Long) */
    public void removeToolContent(Long toolContentId, boolean removeSessionData) throws SessionDataExistsException,
	    ToolException {
	TwitterContent twitterContent = getAndCheckIDandObject(toolContentId);
	// if session data exist and removeSessionData=false, throw an exception
	if (!twitterContent.getTwitterSessions().isEmpty() && !removeSessionData) {
	    throw new SessionDataExistsException(
		    "Delete failed: There is session data that belongs to this tool content id");
	}

	// remove any attachments that belong to this tool entry
	Set attachments = twitterContent.getTwitterAttachments();
	Iterator i = attachments.iterator();
	while (i.hasNext()) {
	    try {
		removeAttachment(twitterContent, (TwitterAttachment) i.next());
	    } catch (RepositoryCheckedException e) {
		// TODO: not sure if suppose to throw another type of exception or not
	    }
	}

	removeTwitter(toolContentId);
    }

    private TwitterContent getAndCheckIDandObject(Long toolContentId) throws ToolException, DataMissingException {
	if (toolContentId == null) {
	    throw new ToolException("Tool content ID is missing. Unable to continue");
	}

	TwitterContent twitterContent = retrieveTwitter(toolContentId);
	if (twitterContent == null) {
	    throw new DataMissingException("No tool content matches this tool content id");
	}

	return twitterContent;
    }

    private TwitterSession getAndCheckSessionIDandObject(Long toolSessionId) throws ToolException,
	    DataMissingException {
	if (toolSessionId == null) {
	    throw new ToolException("Tool session ID is missing. Unable to continue");
	}

	TwitterSession twitterSession = retrieveTwitterSession(toolSessionId);
	if (twitterSession == null) {
	    throw new DataMissingException("No tool session matches this tool session id");
	}

	return twitterSession;
    }

    /*
     * private void checkSessionIDandObject(Long toolSessionId) throws ToolException, DataMissingException { if
     * (toolSessionId == null) throw new ToolException("Tool session ID is missing. Unable to continue");
     * 
     * TwitterSession twitterSession = retrieveTwitterSession(toolSessionId); if (twitterSession == null) throw new
     * DataMissingException("No tool session matches this tool session id"); }
     */

    /**
     * Export the XML fragment for the tool's content, along with any files needed for the content.
     * 
     * @throws DataMissingException
     *                 if no tool content matches the toolSessionId
     * @throws ToolException
     *                 if any other error occurs
     */

    public void exportToolContent(Long toolContentId, String rootPath) throws DataMissingException, ToolException {
	TwitterContent toolContentObj = twitterContentDAO.findTwitterContentById(toolContentId);
	if (toolContentObj == null) {
	    Long defaultContentId = getToolDefaultContentIdBySignature(TwitterConstants.TOOL_SIGNATURE);
	    toolContentObj = retrieveTwitter(defaultContentId);
	}
	if (toolContentObj == null) {
	    throw new DataMissingException("Unable to find default content for the twitter tool");
	}

	try {
	    // set ResourceToolContentHandler as null to avoid copy file node in repository again.
	    toolContentObj = TwitterContent.newInstance(toolContentObj, toolContentId, null);
	    toolContentObj.setTwitterSessions(null);
	    exportContentService.registerFileClassForExport(TwitterAttachment.class.getName(), "uuid", "versionId");
	    exportContentService.exportToolContent(toolContentId, toolContentObj, twitterToolContentHandler, rootPath);
	} catch (ExportToolContentException e) {
	    throw new ToolException(e);
	} catch (ItemNotFoundException e) {
	    throw new ToolException(e);
	} catch (RepositoryCheckedException e) {
	    throw new ToolException(e);
	}
    }

    /**
     * Import the XML fragment for the tool's content, along with any files needed for the content.
     * 
     * @throws ToolException
     *                 if any other error occurs
     */
    public void importToolContent(Long toolContentId, Integer newUserUid, String toolContentPath, String fromVersion,
	    String toVersion) throws ToolException {
	try {
	    exportContentService.registerFileClassForImport(TwitterAttachment.class.getName(), "uuid", "versionId",
		    "filename", "fileProperty", null, null);

	    Object toolPOJO = exportContentService.importToolContent(toolContentPath, twitterToolContentHandler,
		    fromVersion, toVersion);
	    if (!(toolPOJO instanceof TwitterContent)) {
		throw new ImportToolContentException(
			"Import Noteice board tool content failed. Deserialized object is " + toolPOJO);
	    }
	    TwitterContent toolContentObj = (TwitterContent) toolPOJO;

	    // reset it to new toolContentId
	    toolContentObj.setTwitterContentId(toolContentId);
	    twitterContentDAO.saveTwitterContent(toolContentObj);
	} catch (ImportToolContentException e) {
	    throw new ToolException(e);
	}
    }

    /**
     * Get the definitions for possible output for an activity, based on the toolContentId. These may be definitions
     * that are always available for the tool (e.g. number of marks for Multiple Choice) or a custom definition created
     * for a particular activity such as the answer to the third question contains the word Koala and hence the need for
     * the toolContentId
     * 
     * @return SortedMap of ToolOutputDefinitions with the key being the name of each definition
     */
    public SortedMap<String, ToolOutputDefinition> getToolOutputDefinitions(Long toolContentId, int definitionType)
    /*public SortedMap<String, ToolOutputDefinition> getToolOutputDefinitions(Long toolContentId)*/
    	throws ToolException {
	return new TreeMap<String, ToolOutputDefinition>();
    }

    /* ===============Methods implemented from ToolSessionManager =============== */

    /**
     * @see org.lamsfoundation.lams.tool.ToolSessionManager#createToolSession(java.lang.Long, java.lang.String,
     *      java.lang.Long)
     */
    public void createToolSession(Long toolSessionId, String toolSessionName, Long toolContentId) throws ToolException {
	if (toolSessionId == null || toolContentId == null) {
	    String error = "Failed to create tool session. The tool session id or tool content id is invalid";
	    throw new ToolException(error);
	}

	if ((twitterContent = retrieveTwitter(toolContentId)) == null) {
	    // use default content
	    TwitterContent defaultContent = retrieveTwitter(getToolDefaultContentIdBySignature(TwitterConstants.TOOL_SIGNATURE));

	    if (defaultContent != null) {
		TwitterSession newSession = new TwitterSession(toolSessionId, toolSessionName, defaultContent,
			new Date(System.currentTimeMillis()), TwitterSession.NOT_ATTEMPTED);
		// saveTwitterSession(newSession);
		defaultContent.getTwitterSessions().add(newSession);
		saveTwitter(defaultContent);

	    } else {
		throw new ToolException("Default content is missing. Unable to create tool session");
	    }
	} else {
	    TwitterSession twitterSession = new TwitterSession(toolSessionId, toolSessionName, twitterContent, new Date(
		    System.currentTimeMillis()), TwitterSession.NOT_ATTEMPTED);

	    twitterContent.getTwitterSessions().add(twitterSession);
	    saveTwitter(twitterContent);
	    // saveTwitterSession(twitterSession);
	}

    }

    /**
     * @see org.lamsfoundation.lams.tool.ToolSessionManager#leaveToolSession(java.lang.Long,
     *      org.lamsfoundation.lams.usermanagement.User)
     */
    public String leaveToolSession(Long toolSessionId, Long learnerId) throws DataMissingException, ToolException {
	getAndCheckSessionIDandObject(toolSessionId);

	return learnerService.completeToolSession(toolSessionId, learnerId);
    }

    /** @see org.lamsfoundation.lams.tool.ToolSessionManager#exportToolSession(java.lang.Long) */
    public ToolSessionExportOutputData exportToolSession(Long toolSessionId) throws ToolException, DataMissingException {
	getAndCheckSessionIDandObject(toolSessionId);
	throw new UnsupportedOperationException("not yet implemented");
    }

    /** @see org.lamsfoundation.lams.tool.ToolSessionManager#exportToolSession(java.util.List) */
    public ToolSessionExportOutputData exportToolSession(List toolSessionIds) throws ToolException,
	    DataMissingException {
	Iterator i = toolSessionIds.iterator();
	if (i.hasNext()) {
	    Long id = (Long) i.next();
	    getAndCheckSessionIDandObject(id);
	}

	throw new UnsupportedOperationException("not yet implemented");
    }

    /** @see org.lamsfoundation.lams.tool.ToolSessionManager#removeToolSession(java.lang.Long) */
    public void removeToolSession(Long toolSessionId) throws DataMissingException, ToolException {
	TwitterSession session = getAndCheckSessionIDandObject(toolSessionId);
	removeSession(session);
    }

    /**
     * Get the tool output for the given tool output names.
     * 
     * @see org.lamsfoundation.lams.tool.ToolSessionManager#getToolOutput(java.util.List<String>, java.lang.Long,
     *      java.lang.Long)
     */
    public SortedMap<String, ToolOutput> getToolOutput(List<String> names, Long toolSessionId, Long learnerId) {
	return new TreeMap<String, ToolOutput>();
    }

    /**
     * Get the tool output for the given tool output name.
     * 
     * @see org.lamsfoundation.lams.tool.ToolSessionManager#getToolOutput(java.lang.String, java.lang.Long,
     *      java.lang.Long)
     */
    public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) {
	return null;
    }

    /* ===============Methods implemented from ToolContentImport102Manager =============== */

    /**
     * Import the data for a 1.0.2 Twitter or HTMLTwitter
     */
    public void import102ToolContent(Long toolContentId, UserDTO user, Hashtable importValues) {
	Date now = new Date();
	TwitterContent toolContentObj = new TwitterContent();
	String content = WebUtil.convertNewlines((String) importValues.get(ToolContentImport102Manager.CONTENT_BODY));
	toolContentObj.setContent(content);
	toolContentObj.setContentInUse(false);
	toolContentObj.setCreatorUserId(user.getUserID().longValue());
	toolContentObj.setDateCreated(now);
	toolContentObj.setDateUpdated(now);
	toolContentObj.setDefineLater(false);
	toolContentObj.setForceOffline(false);
	toolContentObj.setTwitterContentId(toolContentId);
	toolContentObj.setOfflineInstructions(null);
	toolContentObj.setOnlineInstructions(null);
	toolContentObj.setTitle((String) importValues.get(ToolContentImport102Manager.CONTENT_TITLE));
	toolContentObj.setReflectOnActivity(false);
	// leave as empty, no need to set them to anything.
	// toolContentObj.setTwitterSessions(twitterSessions);
	// toolContentObj.setTwitterAttachments(twitterAttachments);
	twitterContentDAO.saveTwitterContent(toolContentObj);
    }

    /** Set the description, throws away the title value as this is not supported in 2.0 */
    public void setReflectiveData(Long toolContentId, String title, String description) throws ToolException,
	    DataMissingException {

	TwitterContent toolContentObj = retrieveTwitter(toolContentId);
	if (toolContentObj == null) {
	    throw new DataMissingException("Unable to set reflective data titled " + title
		    + " on activity toolContentId " + toolContentId + " as the tool content does not exist.");
	}

	toolContentObj.setReflectOnActivity(Boolean.TRUE);
	toolContentObj.setReflectInstructions(description);
    }

    // =========================================================================================

    public Long getToolDefaultContentIdBySignature(String toolSignature) {
	Long contentId = null;
	contentId = new Long(toolService.getToolDefaultContentIdBySignature(toolSignature));
	if (contentId == null) {
	    String error = "Could not retrieve default content id for this tool";
	    TwitterServicePOJO.log.error(error);
	    throw new TwitterApplicationException(error);
	}
	return contentId;
    }

    /* =============== Used by Spring to "inject" the linked objects =============== */

    /*
     * public ITwitterContentDAO getTwitterContentDAO() { return twitterContentDAO; }
     */
    public void setTwitterContentDAO(ITwitterContentDAO twitterContentDAO) {
	this.twitterContentDAO = twitterContentDAO;
    }

    /*
     * public ITwitterSessionDAO getTwitterSessionDAO() { return twitterSessionDAO; }
     */
    public void setTwitterSessionDAO(ITwitterSessionDAO twitterSessionDAO) {
	this.twitterSessionDAO = twitterSessionDAO;
    }

    /*
     * public ITwitterUserDAO getTwitterUserDAO() { return twitterUserDAO; }
     */
    public void setTwitterUserDAO(ITwitterUserDAO twitterUserDAO) {
	this.twitterUserDAO = twitterUserDAO;
    }
    
    /*
     * public ITwitterUserTweetDAO getTwitterUserTweetDAO() { return twitterUserTweetDAO; }
     */
    public void setTwitterUserTweetDAO(ITwitterUserTweetDAO twitterUserTweetDAO) {
	this.twitterUserTweetDAO = twitterUserTweetDAO;
    }

    /**
     * @return Returns the learnerService.
     */
    /*
     * public ILearnerService getLearnerService() { return learnerService; }
     */
    /**
     * @param learnerService
     *                The learnerService to set.
     */
    public void setLearnerService(ILearnerService learnerService) {
	this.learnerService = learnerService;
    }

    /*
     * public ITwitterAttachmentDAO getTwitterAttachmentDAO() { return twitterAttachmentDAO; }
     */

    public void setTwitterAttachmentDAO(ITwitterAttachmentDAO twitterAttachmentDAO) {
	this.twitterAttachmentDAO = twitterAttachmentDAO;
    }

    /**
     * @param toolService
     *                The toolService to set.
     */
    public void setToolService(ILamsToolService toolService) {
	this.toolService = toolService;
    }

    public IToolContentHandler getTwitterToolContentHandler() {
	return twitterToolContentHandler;
    }

    public void setTwitterToolContentHandler(IToolContentHandler twitterToolContentHandler) {
	this.twitterToolContentHandler = twitterToolContentHandler;
    }

    public IExportToolContentService getExportContentService() {
	return exportContentService;
    }

    public void setExportContentService(IExportToolContentService exportContentService) {
	this.exportContentService = exportContentService;
    }

    public ICoreNotebookService getCoreNotebookService() {
	return coreNotebookService;
    }

    public void setCoreNotebookService(ICoreNotebookService coreNotebookService) {
	this.coreNotebookService = coreNotebookService;
    }

    /* =============== Wrappers Methods for Notebook Service (Reflective Option) =============== */

    public Long createNotebookEntry(Long id, Integer idType, String signature, Integer userID, String entry) {
	return coreNotebookService.createNotebookEntry(id, idType, signature, userID, "", entry);
    }

    public NotebookEntry getEntry(Long id, Integer idType, String signature, Integer userID) {

	List<NotebookEntry> list = coreNotebookService.getEntry(id, idType, signature, userID);
	if (list == null || list.isEmpty()) {
	    return null;
	} else {
	    return list.get(0);
	}
    }

    /**
     * @param notebookEntry
     */
    public void updateEntry(NotebookEntry notebookEntry) {
	coreNotebookService.updateEntry(notebookEntry);
    }

    public Class[] getSupportedToolOutputDefinitionClasses(int definitionType) {
	return null;
    }
}
