/*
 * Copyright 2010 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.sample.expenses.server.domain;

import com.google.appengine.api.datastore.Cursor;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;

import org.datanucleus.store.appengine.query.JPACursorHelper;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Query;
import javax.persistence.Version;

/**
 * Models an expense report.
 */
@Entity
public class ReportBack {

  private static Cache cache;

  private static final Logger log = Logger.getLogger(ReportBack.class.getName());

  /**
   * The total number of reports in the database.
   */
  private static long REPORT_COUNT = 2;

  public static long countReports() {
    EntityManager em = entityManager();
    try {
      return ((Number) em.createQuery("select count(o) from Report o").getSingleResult()).longValue();
    } finally {
      em.close();
    }
  }

  public static long countReportsBySearch(Long employeeId, String department,
      String startsWith) {
    EntityManager em = entityManager();
    try {
      Query query = queryReportsBySearch(em, employeeId, department,
          startsWith, null, true);
      if (query == null) {
        return REPORT_COUNT;
      }
      long count = ((Number) query.getSingleResult()).longValue();
      return count;
    } finally {
      em.close();
    }
  }

  public static final EntityManager entityManager() {
    return EMF.get().createEntityManager();
  }

  @SuppressWarnings("unchecked")
  public static List<ReportBack> findAllReports() {
    EntityManager em = entityManager();
    try {
      List<ReportBack> reportList = em.createQuery("select o from Report o").getResultList();
      // force it to materialize
      reportList.size();
      return reportList;
    } finally {
      em.close();
    }
  }

  public static ReportBack findReport(Long id) {
    if (id == null) {
      return null;
    }
    EntityManager em = entityManager();
    try {
      return em.find(ReportBack.class, id);
    } finally {
      em.close();
    }
  }

  @SuppressWarnings("unchecked")
  public static List<ReportBack> findReportEntries(int firstResult, int maxResults) {
    EntityManager em = entityManager();
    try {
      List<ReportBack> reportList = em.createQuery("select o from Report o").setFirstResult(
          firstResult).setMaxResults(maxResults).getResultList();
      // force it to materialize
      reportList.size();
      return reportList;
    } finally {
      em.close();
    }
  }

  @SuppressWarnings("unchecked")
  public static List<ReportBack> findReportEntriesBySearch(Long employeeId,
      String department, String startsWith, String orderBy, int firstResult,
      int maxResults) {
    EntityManager em = entityManager();
    try {
      Query query = queryReportsBySearch(em, employeeId, department,
          startsWith, orderBy, false);

      // Try to get the memcache
      if (cache == null) {
        try {
          CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
          cache = cacheFactory.createCache(Collections.emptyMap());
        } catch (CacheException e) {
          log.warning("Exception retrieving memcache instance: " + e);
        }
      }

      // Try to get a cursor for the current query
      String encodedCursor = null;
      if (cache != null) {
        String key = createKey(employeeId, department, startsWith, orderBy,
            firstResult);
        encodedCursor = (String) cache.get(key);
      }

      if (encodedCursor != null) {
        // Got a cursor, use it
        Cursor cursor = Cursor.fromWebSafeString(encodedCursor);
        query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
        query.setFirstResult(0);
      } else if (firstResult + maxResults < 1000) {
        // Results may be retrieved directly using "OFFSET"
        query.setHint(JPACursorHelper.CURSOR_HINT, null);
        query.setFirstResult(firstResult);
      } else {
        // Skip results
        int pos = (firstResult / 1000) * 1000;
        Cursor trialCursor = null;
        while (pos > 0) {
          String trialKey = createKey(employeeId, department, startsWith,
              orderBy, pos);
          String trialEncodedCursor = (String) cache.get(trialKey);
          if (trialEncodedCursor != null) {
            trialCursor = Cursor.fromWebSafeString(trialEncodedCursor);
            break;
          }
          pos -= 1000;
        }

        // If trialCursor is null, we'll start searching from result 0
        query.setHint(JPACursorHelper.CURSOR_HINT, trialCursor);
        while (firstResult > pos) {
          int min = Math.min(firstResult - pos, 1000);
          
          // If we need to skip more than 1000 records, ensure the
          // breaks occur at multiples of 1000 in order to increase the
          // chances of reusing cursors from the memcache
          if (pos + min < firstResult) {
            int mod = (pos + min) % 1000;
            min -= mod;
          }
          
          query.setMaxResults(min);
          List<ReportBack> results = query.getResultList();
          int count = results.size();
          if (count == 0) {
            break;
          }
          pos += count;
          
          // Save the cursor for later
          Cursor cursor = JPACursorHelper.getCursor(results);
          if (cache != null) {
            String key = createKey(employeeId, department, startsWith, orderBy,
                pos);
            cache.put(key, cursor.toWebSafeString());
          }
          
          query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
        }
      }
      
      query.setMaxResults(maxResults);

      List<ReportBack> reportList = query.getResultList();
      // force it to materialize
      reportList.size();
      
      Cursor cursor = JPACursorHelper.getCursor(reportList);
      if (cache != null) {
        int pos = firstResult + reportList.size();
        String key = createKey(employeeId, department, startsWith, orderBy, pos);
        cache.put(key, cursor.toWebSafeString());
      }
      
      return reportList;
    } finally {
      em.close();
    }
  }

  @SuppressWarnings("unchecked")
  public static List<ReportBack> findReportsByEmployee(Long employeeId) {
    EntityManager em = entityManager();
    try {
      Query query = em.createQuery("select o from Report o where o.reporterKey =:reporterKey");
      query.setParameter("reporterKey", employeeId);
      List<ReportBack> reportList = query.getResultList();
      // force it to materialize
      reportList.size();
      return reportList;
    } finally {
      em.close();
    }
  }

  private static String createKey(Long employeeId, String department,
      String startsWith, String orderBy, int firstResult) {
    return "" + employeeId + "+" + encode(department) + "+"
        + encode(startsWith) + "+" + encode(orderBy) + "+" + firstResult;
  }

  /**
   * Returns a String based on an input String that provides the following
   * guarantees.
   * 
   * <ol>
   * <li>The result contains no '+' characters
   * <li>Distinct inputs always produce distinct results
   * </ol>
   * 
   * <p>
   * Note that the transformation is not required to be reversible.
   * 
   * @param s the input String
   * @return a String suitable for use as part of a a memcache key
   */
  private static String encode(String s) {
    if (s == null) {
      return "";
    }
    s = s.replace("@", "@@");
    s = s.replace("+", "@");
    return s;
  }

  /**
   * Query for reports based on the search parameters. If startsWith is
   * specified, the results will not be ordered.
   * 
   * @param em the {@link EntityManager} to use
   * @param employeeId the employee id
   * @param department the department to search
   * @param startsWith the starting string
   * @param orderBy the order of the results
   * @param isCount true to query on the count only
   * @return the query, or null to return full report count.
   */
  private static Query queryReportsBySearch(EntityManager em, Long employeeId,
      String department, String startsWith, String orderBy, boolean isCount) {
    // Determine which parameters to include.
    boolean isFirstStatement = true;
    boolean hasEmployee = employeeId != null && employeeId >= 0;
    boolean hasDepartment = !hasEmployee && department != null
        && department.length() > 0;
    boolean hasStartsWith = startsWith != null && startsWith.length() > 0;

    // If we are counting and we don't have any query parameters, return null
    // to force #countReportsBySearch to return the full Report count.
    if (isCount && !hasEmployee && !hasDepartment && !hasStartsWith) {
      return null;
    }

    // Construct the query string.
    String retValue = isCount ? "count(o)" : "o";
    String queryString = "select " + retValue + " from Report o";
    if (hasEmployee) {
      queryString += isFirstStatement ? " WHERE" : " AND";
      isFirstStatement = false;
      queryString += " o.reporterKey =:reporterKey";
    }
    if (hasDepartment) {
      queryString += isFirstStatement ? " WHERE" : " AND";
      isFirstStatement = false;
      queryString += " o.department =:department";
    }
    if (hasStartsWith) {
      queryString += isFirstStatement ? " WHERE" : " AND";
      isFirstStatement = false;
      queryString += " o.purposeLowerCase >=:startsWith";
      queryString += " AND o.purposeLowerCase <=:startsWithZ";
    }
    if (!hasStartsWith && orderBy != null && orderBy.length() >= 0) {
      queryString += " ORDER BY " + orderBy;
    }

    // Construct the query;
    Query query = em.createQuery(queryString);
    if (hasEmployee) {
      query.setParameter("reporterKey", employeeId);
    }
    if (hasDepartment) {
      query.setParameter("department", department);
    }
    if (hasStartsWith) {
      String startsWithLc = startsWith.toLowerCase();
      query.setParameter("startsWith", startsWithLc);
      query.setParameter("startsWithZ", startsWithLc + "zzzzzz");
    }
    return query;
  }

  // @JoinColumn
  private Long approvedSupervisorKey;

  private Date created;

  private String department;

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String notes;

  private String purpose;

  /**
   * Store a lower case version of the purpose for searching.
   */
  @SuppressWarnings("unused")
  private String purposeLowerCase;

  /**
   * Store reporter's key instead of reporter. See:
   * http://code.google.com/appengine
   * /docs/java/datastore/relationships.html#Unowned_Relationships
   */
  // @JoinColumn
  private Long reporterKey;

  @Version
  @Column(name = "version")
  private Integer version;

  public Long getApprovedSupervisorKey() {
    return approvedSupervisorKey;
  }

  public Date getCreated() {
    return this.created;
  }

  public String getDepartment() {
    return this.department;
  }

  public Long getId() {
    return this.id;
  }

  public String getNotes() {
    return this.notes;
  }

  public String getPurpose() {
    return this.purpose;
  }

  public Long getReporterKey() {
    return this.reporterKey;
  }

  public Integer getVersion() {
    return this.version;
  }

  public void persist() {
    EntityManager em = entityManager();
    try {
      em.persist(this);
    } finally {
      em.close();
    }
  }

  public void remove() {
    EntityManager em = entityManager();
    try {
      ReportBack attached = em.find(ReportBack.class, this.id);
      em.remove(attached);
    } finally {
      em.close();
    }
  }

  public void setApprovedSupervisorKey(Long approvedSupervisorKey) {
    this.approvedSupervisorKey = approvedSupervisorKey;
  }

  public void setCreated(Date created) {
    this.created = created;
  }

  public void setDepartment(String department) {
    this.department = department;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public void setNotes(String notes) {
    this.notes = notes;
  }

  public void setPurpose(String purpose) {
    this.purpose = purpose;
    this.purposeLowerCase = purpose == null ? "" : purpose.toLowerCase();
  }

  public void setReporterKey(Long reporter) {
    this.reporterKey = reporter;
  }

  public void setVersion(Integer version) {
    this.version = version;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("Id: ").append(getId()).append(", ");
    sb.append("Version: ").append(getVersion()).append(", ");
    sb.append("Created: ").append(getCreated()).append(", ");
    sb.append("Department: ").append(getDepartment()).append(", ");
    sb.append("Notes: ").append(getNotes()).append(", ");
    sb.append("Purpose: ").append(getPurpose()).append(", ");
    sb.append("Reporter: ").append(getReporterKey()).append(", ");
    sb.append("ApprovedSupervisor: ").append(getApprovedSupervisorKey());
    return sb.toString();
  }
}
