/*
 * Copyright (c) 2006-2013 by Public Library of Science
 * http://plos.org
 * http://ambraproject.org
 *
 * 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 org.ambraproject.rhino.service.impl;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.ambraproject.models.Article;
import org.ambraproject.models.Linkback;
import org.ambraproject.models.Trackback;
import org.ambraproject.rhino.identity.ArticleIdentity;
import org.ambraproject.rhino.rest.MetadataFormat;
import org.ambraproject.rhino.service.LinkbackReadService;
import org.ambraproject.rhino.util.response.ResponseReceiver;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.support.DataAccessUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;

public class LinkbackReadServiceImpl extends AmbraService implements LinkbackReadService {

  private static class ArticleListView {
    private final String doi;
    private final String title;
    private final String articleUrl;
    private final long linkbackCount;
    private final Date mostRecentLinkback;

    private ArticleListView(Object[] queryResult) {
      this.doi = (String) queryResult[0];
      this.title = (String) queryResult[1];
      this.articleUrl = (String) queryResult[2];
      this.linkbackCount = (Long) queryResult[3];
      this.mostRecentLinkback = (Date) queryResult[4];
    }
  }

  private static Function<Object[], ArticleListView> AS_VIEW = new Function<Object[], ArticleListView>() {
    @Override
    public ArticleListView apply(Object[] input) {
      return new ArticleListView(input);
    }
  };

  @Override
  public void listByArticle(ResponseReceiver receiver, MetadataFormat format, OrderBy orderBy) throws IOException {
    List<Object[]> results = hibernateTemplate.find(""
        + "select a.doi, a.title, a.url, count(distinct p.ID) as linkbackCount, max(p.created) as mostRecentLinkback "
        + "from Pingback as p, Article as a where p.articleID = a.ID order by mostRecentLinkback desc");
    writeJson(receiver, Lists.transform(results, AS_VIEW));
  }

  @Override
  public void read(ResponseReceiver receiver, ArticleIdentity article, MetadataFormat format) throws IOException {
    Preconditions.checkNotNull(article);
    long articleId = DataAccessUtils.longResult(hibernateTemplate.findByCriteria(
        DetachedCriteria.forClass(Article.class)
            .add(Restrictions.eq("doi", article.getKey()))
            .setProjection(Projections.property("ID"))));
    List<?> results = hibernateTemplate.findByCriteria(
        DetachedCriteria.forClass(Linkback.class)
            .add(Restrictions.eq("articleID", articleId))
            .addOrder(Order.asc("created"))
    );
    writeJson(receiver, results);
  }

  private static ImmutableMap<String, Object> view(Article article, Linkback linkback) {
    ImmutableMap.Builder<String, Object> view = ImmutableMap.<String, Object>builder();
    view.put("articleDoi", article.getDoi())
        .put("url", linkback.getUrl())
        .put("title", linkback.getTitle())
        .put("created", linkback.getCreated())
        .put("lastModified", linkback.getLastModified());
    if (linkback instanceof Trackback) {
      Trackback trackback = (Trackback) linkback;
      view.put("blogName", trackback.getBlogName())
          .put("excerpt", trackback.getExcerpt());
    }
    return view.build();
  }

}

@@ -1495,31 +1495,8 @@
 on;%0A
-import java.util.Date;%0A
 impo
@@ -1666,22 +1666,22 @@
 e final 
-String
+Object
  doi;%0A  
@@ -1696,22 +1696,22 @@
 e final 
-String
+Object
  title;%0A
@@ -1728,22 +1728,22 @@
 e final 
-String
+Object
  article
@@ -1765,20 +1765,22 @@
 e final 
-long
+Object
  linkbac
@@ -1805,20 +1805,22 @@
 e final 
-Date
+Object
  mostRec
@@ -1901,25 +1901,16 @@
 is.doi =
- (String)
  queryRe
@@ -1936,25 +1936,16 @@
 .title =
- (String)
  queryRe
@@ -1980,17 +1980,8 @@
 rl =
- (String)
  que
@@ -2023,15 +2023,8 @@
 nt =
- (Long)
  que
@@ -2071,15 +2071,8 @@
 ck =
- (Date)
  que
@@ -2444,24 +2444,346 @@
 Exception %7B%0A
+    // Here is what this is intended to do, in SQL:%0A    //  SELECT article.doi, article.title, pbcount.count%0A    //  FROM article INNER JOIN%0A    //    (SELECT COUNT(url) AS count, articleID FROM pingback GROUP BY articleId) AS pbcount%0A    //  ON article.articleID = pbcount.articleID%0A    //  ORDER BY pbcount.count DESC;%0A%0A
     List%3CObj
@@ -2843,16 +2843,25 @@
 %22select 
+distinct 
 a.doi, a
@@ -2879,53 +2879,106 @@
 rl, 
-count(distinct p.ID) as linkbackCount,
+%22%0A        + %22  (select count(*) from Pingback where articleID = a.ID), %22%0A        + %22  (select
  max(
-p.
 crea
@@ -2986,29 +2986,45 @@
 ed) 
-as mostRecentLink
+from Ping
 back
+ where articleID = a.ID)
  %22%0A 
@@ -3094,41 +3094,8 @@
 a.ID
- order by mostRecentLinkback desc
 %22);%0A
@@ -3767,17 +3767,18 @@
 r(Order.
-a
+de
 sc(%22crea

Debug pingback query