package zall;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import zall.bean.Folder;
import zall.bean.Image;
import zall.bean.Media;
import zall.bean.User;
import zall.util.ZalleryEmail;
import zutil.net.smtp.Email;
import zall.util.msg.UserMessage;
import zall.util.msg.UserMessage.MessageType;
import zutil.db.DBConnection;
import zutil.log.LogUtil;

public class Zallery extends HttpServlet{
	private static Logger logger = LogUtil.getLogger();

	public static final String VERSION = "1.0.0";

	public static String WEBSITE_NAME = "Example.com";
	public static String WEBSITE_URL = "http://example.com";
	public static String ROOT_PATH = "";
	public static String DATA_PATH = "";

	/**
	 * Config Options:
	 * <br>- WEBSITE_NAME
	 * <br>- WEBSITE_URL
	 * <br>- SMTP_HOST
	 * <br>- DATA_PATH
	 */
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		// java:comp/env
		ROOT_PATH = config.getServletContext().getRealPath("/");
        try {
            Context context = new InitialContext();
            // Check if Zallery has been properly configured
			if ("C:\\\\data".equals(context.lookup("java:comp/env/DATA_PATH")))
				throw new ServletException("Zallery has not been properly configured, set proper configuration in Zaller.xml context file.");

            WEBSITE_NAME = (String)context.lookup("java:comp/env/WEBSITE_NAME");
            WEBSITE_URL = (String)context.lookup("java:comp/env/WEBSITE_URL");
            if( WEBSITE_URL.charAt(WEBSITE_URL.length()-1) != '/')
                WEBSITE_URL += "/";
            ZalleryEmail.setSMTPHost( (String)context.lookup("java:comp/env/SMTP_HOST") );
            DATA_PATH = (String)context.lookup("java:comp/env/DATA_PATH");

            LogUtil.setLevel("zall", Level.FINEST);
            //LogUtil.setLevel("zutil", Level.FINEST);
        } catch (NamingException e) {
            throw new ServletException(e);
        }
	}
	
	public void destroy(){

	}

	public  void doGet(HttpServletRequest request, HttpServletResponse  response) throws ServletException{
		DBConnection db = null;
		try{
			doGet(request, response, db = getDB());
		} finally{
			if(db != null) db.close();
		}
	}

	public  void doGet(HttpServletRequest request, HttpServletResponse  response, DBConnection db) throws ServletException{
		try{
			response.setContentType("text/html");
			HttpSession session = request.getSession();
			String page = new File(request.getRequestURI()).getName();
			request.setAttribute("page", page);
			User user = (User) session.getAttribute("user");
			String action = request.getParameter("action");
			if( action == null ) action = "";
			UserMessage msgs = UserMessage.getUserMessage(session);

			
			// Verify email address
			if( action.equalsIgnoreCase("verfemail") ){
				User verfUser = User.load(db, Long.parseLong(request.getParameter("id")));
				if (verfUser != null) {
					if( verfUser.verifyEmail(request.getParameter("hash")) ){
						ZalleryEmail.sendNewUserRegistrationToAdmin(verfUser, db);
						verfUser.save(db);
						msgs.add(MessageType.INFO, "Your email has been successfully verified.");
						msgs.add(MessageType.WARNING, "The account is waiting account activation by an admin.");
					}
					else
						msgs.add(MessageType.ERROR, "Email verification failed!");
				}
				else msgs.add(MessageType.ERROR, "Invalid user id: "+request.getParameter("id"));
			}
			// auth with cookie
			if( user == null ){
				user = User.loadByCookie(request, db, getCookieValue(request.getCookies(), "sessionHash") );
				if(user != null){
					logger.info("Used cookies to auth User: \""+user.getName()+"\".");
					session.setAttribute("user", user);
				}
			}

			if( user == null && ( !page.startsWith("register") && !page.startsWith("login") )){
				//response.sendRedirect("login?redirect=\""+getUrl(request)+"\"");
				response.sendRedirect("login");	
				return;
			}
			// validate user or Logout
			if( user != null && ( !user.valid(request) || page.startsWith("logout") )){
				logger.info("Logging Out User: \""+user.getName()+"\".");
				session.invalidate();
				session = request.getSession( true );
				msgs.setSession( session );
				user.logout( response );
				
				if( !user.isEmailVerified() )
					msgs.add(MessageType.WARNING, "Your email has not been verified!");
				else if( !user.isEnabled() )
					msgs.add(MessageType.ERROR, "Your account is disabled! Please contact the website administrator."); 
				else
					msgs.add(MessageType.WARNING, "Your have been logged out.");
				user = null;
				response.sendRedirect("login");
				return;
			}		
			
			//**********************************************************
			String include_jsp = null;
			if( user != null ){
				logger.finest("Valid user: \""+user.getName()+"\"");
				// Import JSP pages
				if(page.startsWith("media")){
					try{
						if( request.getParameter("id") == null && request.getParameter("type") == null){
							msgs.add(MessageType.ERROR, "Missing parameters!");
							return;
						}
						int id = Integer.parseInt( request.getParameter("id") );
						Media media = Media.load(db, request.getParameter("type"), id);
						
						request.setAttribute("media", media);
						include_jsp = "media.jsp";
					}catch(NumberFormatException e){ logger.log(Level.FINE, "", e); }
				}
				else if(page.startsWith("login")){
					include_jsp = "login.jsp";
				}
				else if(page.startsWith("profile")){
					if( request.getParameter("id") != null ){
						User profile_user = User.load(db, Long.parseLong( request.getParameter("id") ));
						if( user.canEdit( profile_user )){
							request.setAttribute("profile_user", profile_user);
							include_jsp = "profile.jsp";
						}else{
							msgs.add(MessageType.ERROR, "You do not have permission to edit this user.");
						}
					}else{
						request.setAttribute("profile_user", user);
						include_jsp = "profile.jsp";
					}
				}
				else if(page.startsWith("users")){
					List<User> users = User.load(db);
					request.setAttribute("users", users);
					include_jsp = "users.jsp";
				}
				else if(page.startsWith("upload")){
					List<Folder> dirList = Folder.load(db, user);
					request.setAttribute("folders", dirList);
					include_jsp = "upload.jsp";
				}
				else if( page.startsWith("slideshow") ){
					Image image = Image.load(db, Integer.parseInt( request.getParameter("id") ));
					request.setAttribute("image", image );
					List<Image> list = Image.loadFolder(db, image.getFolder());
					
					request.setAttribute("image", image);
					request.setAttribute("images", list);
					
					include_jsp = "slideshow.jsp";
				}
				else { // if(page.startsWith("gallery"))
					Folder folder = null;
					if(request.getParameter("folder") != null && !request.getParameter("folder").equalsIgnoreCase("null"))
						folder = Folder.load(db, Long.parseLong(request.getParameter("folder")) );
					else{
						folder = Folder.loadRoot(db, user);
						// Setup new root folder
						if( folder == null ){
							folder = Folder.genRoot();
							folder.save(db);
						}
					}
					List<Media> list = Media.load(db, folder);
					List<Folder> subFolders = Folder.loadSubFolders(db, folder.getId(), user);
					
					//session.setAttribute("user", user);
					request.setAttribute("folder", folder);
					request.setAttribute("subfolders", subFolders);
					request.setAttribute("media", list);
					
					include_jsp = "gallery.jsp";
				}
			}
			else if(page.startsWith("register")){
				include_jsp = "register.jsp";
			}
			else if(page.startsWith("login")){
				include_jsp = "login.jsp";
			}
			else{
				//response.sendRedirect("login?redirect=\""+getUrl(request)+"\"");
				response.sendRedirect("login");
				return;
			}
			

			include("header.jsp", request, response);
			if( include_jsp != null )
				include(include_jsp, request, response);
			include("footer.jsp", request, response);
		} catch (Exception e) {
			logger.severe(e.getMessage());
			System.out.flush();
			throw new ServletException(e);
		} finally{
			if(db != null) db.close();
		}
	}

	public  void doPost(HttpServletRequest request, HttpServletResponse  response) throws ServletException{
		try {
			include("ajax", request, response);
			
			// RequestDispatcher include header read only workaround
			HttpSession session = request.getSession();
			User user = (User) session.getAttribute("user");
			if( user != null ){
				Cookie c = new Cookie("sessionHash", user.getSessionHash() );
				c.setMaxAge(5*24*60*60); // 5 days
				response.addCookie( c );
			}
			
			// Do the output
			doGet(request, response);

		} catch (Exception e) {
			logger.severe(e.getMessage());
			throw new ServletException(e);
		}
	}

	public static DBConnection getDB() throws ServletException{
		try {
			return new DBConnection("jdbc/mysql");
		} catch (Exception e) {
			throw new ServletException(e);
		}
	}

	protected void include(String url, HttpServletRequest request, HttpServletResponse  response) throws ServletException, IOException{
		RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/"+url);
		if (dispatcher != null)
			dispatcher.include(request, response);
	}

	public static String getCookieValue(Cookie[] cookies, String name) {
		if( cookies == null )
			return null;
		for(Cookie cookie : cookies) {
			if ( name.equals(cookie.getName()) )
				return cookie.getValue();
		}
		return null;
	}

	public static String getWebsiteName() {
		return WEBSITE_NAME;
	}

	public static String getWebsiteURL() {
		return WEBSITE_URL;
	}
	
	// /mywebapp/servlet/MyServlet/a/b;c=123?d=789
	public static String getUrl(HttpServletRequest req) {
	    String reqUri = req.getRequestURI().toString();
	    String queryString = req.getQueryString();   // d=789
	    if (queryString != null) {
	        reqUri += "?"+queryString;
	    }
	    return reqUri;
	}
}
