package library.web;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.validation.Valid;

import library.model.LibraryItem;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/library")
public class LibraryController {
	private static List<LibraryItem> library = new ArrayList<LibraryItem>();
	private static Connection conn = null;
	private String error = "";
	private boolean hasError = false;

	LibraryController() {
		getLibrary();
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView showLibrary(
			@RequestParam(value = "search", required = false) String search) {
		ModelAndView mv = new ModelAndView();
		mv.setViewName("library");
		if (search != null) {
			mv.addObject("search", true);
		} else {
			mv.addObject("search", false);
		}
		mv.addObject("library", getLibraryResult(search));
		if (hasError)
			mv.addObject("error", getError());
		else
			mv.addObject("error", "");
		return mv;
	}

	@RequestMapping(value = "/entry", method = RequestMethod.GET)
	public ModelAndView showForm(
			@RequestParam(value = "id", required = false) Integer id) {
		ModelAndView mv = new ModelAndView();
		LibraryItem entry = null;
		if (id != null) {
			entry = getEntryById(id);
			mv.setViewName("entryFormPage");
		}
		if (entry == null) {
			entry = new LibraryItem();
			mv.setViewName("entryForm");
		}
		mv.addObject("entry", entry);
		return mv;
	}

	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public String processForm(
			@Valid @ModelAttribute("entry") LibraryItem entry,
			BindingResult result, Model model) {
		if (result.hasErrors()) { // vigade korral naitame vormi uuesti
			return "entryFormPage";
		}
		if (entry.getId() != -1) {
			editEntry(entry);
		} else {
			addEntry(entry);
		}
		return "redirect:/library";
	}

	private List<LibraryItem> getLibraryResult(String search) {
		getLibrary();
		if (search != null)
			if (!search.equals("")) {
				String searchLine = ".*" + search.toLowerCase() + ".*";
				ArrayList<LibraryItem> returnList = new ArrayList<LibraryItem>();
				for (LibraryItem item : library) {
					if (item.getTitle().toLowerCase().matches(searchLine)
							| item.getAuthor().toLowerCase()
									.matches(searchLine)
							| item.getGenre().toLowerCase().matches(searchLine)
							| item.getType().toLowerCase().matches(searchLine)
							| item.getComment().toLowerCase().matches(
									searchLine)
							| item.getYear().toLowerCase().matches(searchLine))
						returnList.add(item);
				}
				return returnList;
			}
		return library;
	}

	@RequestMapping(value = "/remove", method = RequestMethod.GET)
	public String removeAddress(@RequestParam(value = "id") Integer id) {
		removeEntry(id);
		return "redirect:/library";
	}

	private LibraryItem getEntryById(int id) {
		for (LibraryItem entry : library) {
			if (entry.getId() == id)
				return entry;
		}

		return null;
	}

	private void getLibrary() {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			if (conn == null || conn.isClosed())
				if (!OpenConnection())
					return;
			ps = conn.prepareStatement("SELECT * FROM `library`;");
			ps.execute();
			rs = ps.getResultSet();
			library.clear();
			while (rs.next()) {
				try {
					library.add(new LibraryItem(rs.getInt("id"), rs
							.getString("title"), rs.getString("author"), rs
							.getString("genre"), rs.getString("type"), rs
							.getString("year"), rs.getString("comment")));
				} catch (SQLException e) {
					// Failed, but get the next one
				}
			}
		} catch (SQLException e) {
			setError("Error: " + e.getMessage());
		} finally {
			if (rs != null)
				try {
					rs.close();
				} catch (SQLException e) {
				}
			if (ps != null)
				try {
					ps.close();
				} catch (SQLException e) {
				}
		}
	}

	private void removeEntry(int id) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			if (conn == null || conn.isClosed())
				if (!OpenConnection())
					return;
			ps = conn.prepareStatement("DELETE FROM `library` WHERE id=" + id
					+ ";");
			ps.execute();
		} catch (SQLException e) {
			setError("Error: " + e.getMessage());
		} finally {
			if (rs != null)
				try {
					rs.close();
				} catch (SQLException e) {
				}
			if (ps != null)
				try {
					ps.close();
				} catch (SQLException e) {
				}
		}
	}

	private void addEntry(LibraryItem entry) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			if (conn == null || conn.isClosed())
				if (!OpenConnection())
					return;
			ps = conn
					.prepareStatement("INSERT INTO `library` (title, author, genre, type, year, comment) VALUES (?,?,?,?,?,?);");
			ps.setString(1, entry.getTitle());
			ps.setString(2, entry.getAuthor());
			ps.setString(3, entry.getGenre());
			ps.setString(4, entry.getType());
			ps.setInt(5, Integer.parseInt(entry.getYear()));
			ps.setString(6, entry.getComment());
			ps.execute();
		} catch (SQLException e) {
			setError("Error: " + e.getMessage());
		} finally {
			if (rs != null)
				try {
					rs.close();
				} catch (SQLException e) {
				}
			if (ps != null)
				try {
					ps.close();
				} catch (SQLException e) {
				}
		}
	}

	private void editEntry(LibraryItem entry) {
		if (entry.getId() == -1)
			return;

		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			if (conn == null || conn.isClosed())
				if (!OpenConnection())
					return;
			ps = conn
					.prepareStatement("UPDATE `library` SET title= ?, author = ?, genre= ?, type= ?, year= ?, comment= ? WHERE id= ?");

			ps.setString(1, entry.getTitle());
			ps.setString(2, entry.getAuthor());
			ps.setString(3, entry.getGenre());
			ps.setString(4, entry.getType());
			ps.setInt(5, Integer.parseInt(entry.getYear()));
			ps.setString(6, entry.getComment());
			ps.setInt(7, entry.getId());
			ps.execute();
		} catch (SQLException e) {
			setError("Error: " + e.getMessage());
		} finally {
			if (rs != null)
				try {
					rs.close();
				} catch (SQLException e) {
				}
			if (ps != null)
				try {
					ps.close();
				} catch (SQLException e) {
				}
		}
	}

	private boolean OpenConnection() {
		try {
			conn = DriverManager
					.getConnection("jdbc:mysql://localhost:3306/home_library",
							"root", "admin");
		} catch (SQLException e) {
			setError("Error: Failed to open connection to database");
			return false;
		}

		return true;
	}

	private void setError(String error) {
		hasError = true;
		this.error = error;
	}

	private String getError() {
		hasError = false;
		return error;
	}
}
