package com.syzton.sunread.controller.bookshelf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javassist.NotFoundException;
import javax.validation.Valid;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
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.bind.annotation.ResponseBody;
import com.syzton.sunread.dto.bookshelf.BookInShelfDTO;
import com.syzton.sunread.dto.bookshelf.BookshelfStatisticsDTO;
import com.syzton.sunread.dto.bookshelf.BookshelfStatisticsDTO.VerifiedBook;
import com.syzton.sunread.dto.common.PageResource;
import com.syzton.sunread.exception.bookshelf.BookInShelfDuplicateVerifiedException;
import com.syzton.sunread.model.book.Book;
import com.syzton.sunread.model.book.Dictionary;
import com.syzton.sunread.model.book.DictionaryType;
import com.syzton.sunread.model.bookshelf.BookInShelf;
import com.syzton.sunread.model.semester.Semester;
import com.syzton.sunread.service.book.BookService;
import com.syzton.sunread.service.book.DictionaryService;
import com.syzton.sunread.service.bookshelf.BookInShelfService;
import com.syzton.sunread.service.semester.SemesterService;
/**
* @author Morgan-Leon
*/
@Controller
@RequestMapping(value = "/api")
public class BookInShelfController {
private static final Logger LOGGER = LoggerFactory.getLogger(BookshelfController.class);
private BookInShelfService service;
private SemesterService semesterService;
private BookService bookService;
private DictionaryService dictionaryService;
@Autowired
public BookInShelfController(BookInShelfService service){
this.service = service;
}
@Autowired
public void SemesterServiceController(SemesterService semesterService){
this.semesterService = semesterService;
}
@Autowired
public void BookController(BookService bookService){
this.bookService = bookService;
}
@Autowired
public void DictionaryController(DictionaryService dictionaryService){
this.dictionaryService = dictionaryService;
}
//Add a Book to bookshelf
@RequestMapping(value = "/bookshelf/{id}/books/{bookId}/bookinshelf", method = RequestMethod.POST)
@ResponseBody
public BookInShelfDTO add(@Valid @RequestBody BookInShelfDTO dto
,@PathVariable("id")Long id, @PathVariable("bookId")Long bookId ) {
LOGGER.debug("Adding a new book to shelf entry with information: {}", dto);
BookInShelf added = service.add(dto,id, bookId);
return added.createDTO();
}
//Delete a book in shelf
@RequestMapping(value = "/bookinshelf/{id}", method = RequestMethod.DELETE)
@ResponseBody
public BookInShelfDTO deleteById(@PathVariable("id") Long id) throws NotFoundException {
LOGGER.debug("Deleting a book in shelf entry with id: {}", id);
BookInShelf deleted = service.deleteById(id);
LOGGER.debug("Deleted book in shelf entry with information: {}", deleted);
return deleted.createDTO();
}
//Delete a book in shelf
@RequestMapping(value = "/bookshelf/{bookshelfId}/books/{bookId}/bookinshelf", method = RequestMethod.DELETE)
@ResponseBody
public BookInShelfDTO deleteByStudentIdAndBookId(@PathVariable("bookshelfId")Long bookshelfId, @PathVariable("bookId")Long bookId) throws NotFoundException, BookInShelfDuplicateVerifiedException {
LOGGER.debug("Deleting a book in shelf entry with id: {}", bookshelfId);
//Boolean update = service.updateReadState(bookshelfId, bookId);
BookInShelf deleted = service.deleteByBookshelfIdAndBookId(bookshelfId, bookId);
LOGGER.debug("Deleted book in shelf entry with information: {}", deleted);
return deleted.createDTO();
}
//Update a book in shelf
@RequestMapping(value = "/bookinshelf/{id}", method = RequestMethod.PUT)
@ResponseBody
public BookInShelfDTO update(@Valid @RequestBody BookInShelfDTO dto,@PathVariable("id") long id) throws NotFoundException {
LOGGER.debug("Adding a new book to shelf entry with information: {}", dto);
BookInShelf updated = service.update(dto,id);
LOGGER.debug("Added a to-do entry with information: {}", updated);
return updated.createDTO();
}
//Get all books in shelf
@RequestMapping(value = "/bookshelf/{id}/bookinshelf", method = RequestMethod.GET)
@ResponseBody
public PageResource<BookInShelf> findAllBooks(@PathVariable("id") long id,
@RequestParam("page") int page,
@RequestParam("size") int size,
@RequestParam("sortBy") String sortBy) throws NotFoundException {
LOGGER.debug("Finding books in shelf entry with id: {}" );
sortBy = sortBy==null?"id": sortBy;
Pageable pageable = new PageRequest(page,size,new Sort(sortBy));
Page<BookInShelf> pageResult = service.findByBookshelfId(pageable,id);
return new PageResource<>(pageResult,"page","size");
}
//Get a Book in bookshelf
@RequestMapping(value = "/bookinshelf/{id}", method = RequestMethod.GET)
@ResponseBody
public BookInShelfDTO findById(@PathVariable("id") Long id) throws NotFoundException {
LOGGER.debug("Finding a book in shelf entry with id: {}", id);
BookInShelf found = service.findById(id);
LOGGER.debug("Found to-do entry with information: {}", found);
return found.createDTO();
}
//Get a Book in bookshelf
@RequestMapping(value = "/bookshelf/{id}/books/{bookId}/bookinshelf", method = RequestMethod.GET)
@ResponseBody
public BookInShelfDTO findByStudentIdAndBookId(@PathVariable("id") Long id,@PathVariable("bookId") Long bookId) throws NotFoundException {
LOGGER.debug("Finding a book in shelf entry with id: {}", id);
BookInShelf found = service.findByStudentIdAndBookId(id, bookId);
if(found.getDeleted())
throw new com.syzton.sunread.exception.common.NotFoundException("The book with name "+found.getBookName()+"had been deleted.");
return found.createDTO();
}
//Get a Book in bookshelf
@RequestMapping(value = "/student/{studentId}/semester/{semesterId}/bookshelfStatistics", method = RequestMethod.GET)
@ResponseBody
public BookshelfStatisticsDTO findBySemester(@PathVariable("studentId") Long studentId,@PathVariable("semesterId") Long semesterId) throws NotFoundException {
LOGGER.debug("Finding a book in shelf entry with id: {}", semesterId);
Semester semester = semesterService.findOne(semesterId);
DateTime startTime = semester.getStartTime();
DateTime endTime = semester.getEndTime();
ArrayList<BookInShelf> founds = service.findByStudentIdAndSemester(studentId, startTime,endTime);
LOGGER.debug("Found to-do entry with information: {}", founds);
return createBookshelfStatisticsDTO(founds, startTime, endTime);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public BookshelfStatisticsDTO createBookshelfStatisticsDTO(ArrayList<BookInShelf> booksInShelves, DateTime startTime, DateTime endTime) {
// Initlizate the dto entity
BookshelfStatisticsDTO dto = new BookshelfStatisticsDTO();
int startMonth = startTime.getMonthOfYear();
int endMonth = endTime.getMonthOfYear();
int monthCount = endMonth - startMonth + ( startMonth < endMonth ? 0 : 12 ) + 1;
dto.monthlyVerifiedNums = new int[monthCount];
dto.monthlyPoints = new int[monthCount];
dto.semesterVerified = new ArrayList<VerifiedBook>();
dto.semesterReadNum = 0;
// Initlizate monthlyVerifiedNums and monthlyPoints
for ( int i = 0; i < monthCount; i ++ ){
dto.monthlyVerifiedNums[i] = 0;
dto.monthlyPoints[i] = 0;
}
// Initlizate the categoriesMap
List<Dictionary> categories = dictionaryService.findByType(DictionaryType.CATEGORY);
Map categoriesMap = new HashMap<Integer, String>();
for ( Dictionary category : categories ){
categoriesMap.put( category.getValue(), category.getName() );
}
// Calculate the dto
for ( BookInShelf bookInShelf : booksInShelves ) {
// Update semesterReadNum
dto.semesterReadNum ++;
// Check if bookInShelf is verified
if ( bookInShelf.getReadState() == true ) {
// The index in both arrays
int index = bookInShelf.getVerifiedTime().getMonthOfYear() - startMonth;
if ( index < 0 ) { index += 12; }
// Update monthlyVerifiedNums
dto.monthlyVerifiedNums[index] ++;
// Update monthlyPoints
dto.monthlyPoints[index] += bookInShelf.getPoint();
// Update the semesterVerified
VerifiedBook verifiedBook = dto.new VerifiedBook();
Book book = bookService.findById(bookInShelf.getBookId());
verifiedBook.bookName = bookInShelf.getBookName();
verifiedBook.author = book.getAuthor();
verifiedBook.wordCount = book.getWordCount();
verifiedBook.point = bookInShelf.getPoint();
verifiedBook.verifiedTime = bookInShelf.getVerifiedTime();
int categoryId = book.getExtra().getCategory();
verifiedBook.category = (String) categoriesMap.get(categoryId);
dto.semesterVerified.add(verifiedBook);
}
}
return dto;
}
public int bookNumDuration(ArrayList<BookInShelf> booksInShelfs, DateTime fromDate, DateTime toDate){
int count = 0;
for (BookInShelf bookInShelf : booksInShelfs) {
if( bookInShelf.getVerifiedTime() != null && isInDuration(bookInShelf.getVerifiedTime(), fromDate, toDate))
count++;
}
return count;
}
public int bookPointsDuration(ArrayList<BookInShelf> bookInShelfs, DateTime fromDate, DateTime toDate) {
int points = 0;
for (BookInShelf bookInShelf : bookInShelfs) {
if(bookInShelf.getVerifiedTime() != null && isInDuration(bookInShelf.getVerifiedTime(), fromDate, toDate))
points+= bookInShelf.getPoint();
}
return points;
}
public boolean isInDuration(DateTime currentTime,DateTime fromDate, DateTime toDate){
if (currentTime.isAfter(fromDate.getMillis())&¤tTime.isBefore(toDate.getMillis())) {
return true;
}
else {
return false;
}
}
}