/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package foam.dao.history;

import foam.core.FObject;
import foam.core.X;
import foam.core.PropertyInfo;
import foam.dao.DAO;
import foam.dao.ProxyDAO;
import foam.dao.SequenceNumberDAO;
import foam.nanos.auth.User;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import static foam.mlang.MLang.EQ;

public class HistoryDAO
    extends ProxyDAO
{
  protected DAO historyDAO_;

  public HistoryDAO(X x, String historyDAO, DAO delegate) {
    this(x, (DAO) x.get(historyDAO), delegate);
  }

  public HistoryDAO(X x, DAO historyDAO, DAO delegate) {
    super(x, delegate);
    historyDAO_ = historyDAO;
  }

  /**
   * Formats a User record to the following string
   * LastName, FirstName (ID)
   * @param user The user to format
   * @return The formatted string
   */
  private String formatUserName(User user) {
    return user.getLastName() +", " +
        user.getFirstName() +
        "(" + user.getId() + ")";
  }

  /**git
   * Returns an array of updated properties
   *
   * @param currentValue current value
   * @param newValue new value
   * @return array of PropertyUpdate objects
   */
  private PropertyUpdate[] getUpdatedProperties(FObject currentValue, FObject newValue) {
    Map diff = currentValue.diff(newValue);
    Iterator i = diff.keySet().iterator();

    int index = 0;
    PropertyUpdate[] updates = new PropertyUpdate[diff.keySet().size()];
    while ( i.hasNext() ) {
      String key = (String) i.next();
      PropertyInfo prop = (PropertyInfo) currentValue.getClassInfo().getAxiomByName(key);
      updates[index++] = new PropertyUpdate(key, prop.f(currentValue), diff.get(key));
    }

    return updates;
  }

  @Override
  public FObject put_(X x, FObject obj) {
    User user = (User) x.get("user");
    FObject current = this.find_(x, obj);

    // add new history record
    Object objectId = ((PropertyInfo) obj.getClassInfo().getAxiomByName("id")).f(obj);
    HistoryRecord historyRecord = new HistoryRecord();
    historyRecord.setObjectId(objectId);
    historyRecord.setUser(formatUserName(user));
    historyRecord.setTimestamp(new Date());
    if ( current != null ) {
      historyRecord.setUpdates(getUpdatedProperties(current, obj));
    }
    historyDAO_.put_(x, historyRecord);

    return super.put_(x, obj);
  }

  @Override
  public FObject remove_(X x, FObject obj) {
    Object objectId = ((PropertyInfo) obj.getClassInfo().getAxiomByName("id")).f(obj);
    historyDAO_.where(EQ(HistoryRecord.OBJECT_ID, objectId)).removeAll();
    return super.remove_(x, obj);
  }
}

@@ -187,17 +187,28 @@
 am.core.
-X
+PropertyInfo
 ;%0Aimport
@@ -214,36 +214,25 @@
 t foam.core.
-PropertyInfo
+X
 ;%0Aimport foa
@@ -332,17 +332,49 @@
 h.User;%0A
+import foam.nanos.logger.Logger;
 %0A
-
 import j
@@ -415,16 +415,16 @@
 erator;%0A
+
 import j
@@ -437,17 +437,16 @@
 il.Map;%0A
-%0A
 import s
@@ -1949,24 +1949,36 @@
 _(x, obj);%0A%0A
+    try %7B%0A  
     // add n
@@ -1995,16 +1995,18 @@
  record%0A
+  
     Obje
@@ -2088,16 +2088,18 @@
 j);%0A    
+  
 HistoryR
@@ -2141,24 +2141,26 @@
 cord();%0A    
+ 
+ 
 historyRecor
@@ -2184,16 +2184,18 @@
 ectId);%0A
+  
     hist
@@ -2231,24 +2231,26 @@
 ame(user));%0A
+  
     historyR
@@ -2285,16 +2285,18 @@
 ));%0A    
+  
 if ( cur
@@ -2308,24 +2308,26 @@
 != null ) %7B%0A
+  
       histor
@@ -2382,22 +2382,27 @@
  obj));%0A
+  
     %7D%0A
+%0A  
     hist
@@ -2432,16 +2432,156 @@
 Record);
+%0A    %7D catch (Throwable t) %7B%0A      Logger l = (Logger) x.get(%22logger%22);%0A      l.error(%22Unexpected error creating history record.%22, t);%0A    %7D
 %0A%0A    re

Make HistoryDAO not fail DAO operation if can't create history record.