package net.fortytwo.twitlogic.persistence;

import info.aduna.iteration.CloseableIteration;
import net.fortytwo.sesametools.ldserver.WebResource;
import net.fortytwo.twitlogic.TwitLogic;
import net.fortytwo.twitlogic.model.Person;
import net.fortytwo.twitlogic.model.User;
import net.fortytwo.twitlogic.services.twitter.TwitterClient;
import net.fortytwo.twitlogic.vocabs.FOAF;
import net.fortytwo.twitlogic.vocabs.TwitlogicVocabulary;
import org.openrdf.model.Literal;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.sail.SailConnection;
import org.openrdf.sail.SailException;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.logging.Logger;

/**
 * @author Joshua Shinavier (http://fortytwo.net)
 */
public class PersonResource extends WebResource {
    private static final Logger LOGGER = TwitLogic.getLogger(PersonResource.class);

    private static final long DEFAULT_EXPIRE_TIME = 24 * 60 * 60 * 1000;

    private static final int DEFAULT_FOLLOWEE_LIMIT = 1000;

    private static final DatatypeFactory DATATYPE_FACTORY;

    static {
        try {
            DATATYPE_FACTORY = DatatypeFactory.newInstance();
        } catch (DatatypeConfigurationException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    private final long expireTime;
    private final int followeeLimit;

    public PersonResource() throws Exception {
        expireTime = TwitLogic.getConfiguration().getLong(TwitLogic.METADATA_EXPIRE_TIME, DEFAULT_EXPIRE_TIME);
        followeeLimit = TwitLogic.getConfiguration().getInt(TwitLogic.METADATA_FOLLOWEE_LIMIT, DEFAULT_FOLLOWEE_LIMIT);
    }

    @Override
    public void preprocessingHook() throws Exception {
        TweetStore store = TweetStore.getInstance();
        TweetStoreConnection c = store.createConnection();
        try {
            ValueFactory vf = store.getSail().getValueFactory();
            SailConnection sc = c.getSailConnection();

            long id = Long.valueOf(selfURI.substring(selfURI.lastIndexOf('/') + 1, selfURI.lastIndexOf('.')));
            User user = new User(id);
            URI personURI = vf.createURI(PersistenceContext.uriOf(new Person(user)));

            // check timestamp
            long lastUpdate = 0;
            CloseableIteration<? extends Statement, SailException> iter
                    = sc.getStatements(personURI, TwitlogicVocabulary.lastUpdatedAt, null, false);
            try {
                if (iter.hasNext()) {
                    lastUpdate = ((Literal) iter.next().getObject()).calendarValue().toGregorianCalendar().getTime().getTime();
                }
            } finally {
                iter.close();
            }

            long now = System.currentTimeMillis();
            if (expireTime > 0 && now - lastUpdate > expireTime) {
                LOGGER.info((0 == lastUpdate ? "setting" : "updating") + " followees of " + personURI);

                // fetch followees
                TwitterClient client = store.getTwitterClient();
                List<User> followees = client.getFollowees(user, followeeLimit);

                URI foafKnows = vf.createURI(FOAF.KNOWS);

                // persist self and foaf:knows edges
                sc.removeStatements(personURI, foafKnows, null);
                for (User f : followees) {
                    sc.addStatement(personURI, foafKnows, vf.createURI(PersistenceContext.uriOf(new Person(f))));
                }

                // update timestamp
                GregorianCalendar cal = new GregorianCalendar();
                cal.setTime(new Date(now));
                Literal obj = sail.getValueFactory().createLiteral(
                        DATATYPE_FACTORY.newXMLGregorianCalendar(cal));
                sc.removeStatements(personURI, TwitlogicVocabulary.lastUpdatedAt, null);
                sc.addStatement(personURI, TwitlogicVocabulary.lastUpdatedAt, obj);

                sc.commit();
            }
        } finally {
            c.close();
        }
    }
}

@@ -2439,17 +2439,18 @@
 pdate = 
-0
+-1
 ;%0A      
@@ -2950,16 +2950,37 @@
       if
+ (-1 == lastUpdate %7C%7C
  (expire
@@ -3021,16 +3021,17 @@
 ireTime)
+)
  %7B%0A     

Expire time tweak