/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.openjpa.audit;

import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import jakarta.persistence.CascadeType;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;

import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.kernel.Audited;
import org.apache.openjpa.kernel.Broker;
import org.apache.openjpa.persistence.Type;

/**
 * An example of an immutable persistent entity that holds a reference to the entity being audited.
 * <br>
 * This entity holds the reference to the entity being audited in a <em>generic</em>
 * sense i.e. it does not know the exact type of the audited entity, but merely that
 * it is a {@link PersistenceCapable} instance.
 * <br>
 * OpenJPA supports such reference by annotating with the {@link #audited reference field} as
 * <tt>@Type(PersistenceCapable.class)</tt>.
 * <br>
 * The audit operation is also represented as a {@link #operation enumerated field}.
 *
 * @author Pinaki Poddar
 *
 */
@Entity
public class AuditedEntry {
	@Id
	@GeneratedValue
	private long id;

	@ManyToOne(cascade=CascadeType.MERGE)
	@Type(PersistenceCapable.class)
	private Object audited;

	@Enumerated(EnumType.STRING)
	private AuditableOperation operation;

	@Temporal(TemporalType.TIMESTAMP)
	private Timestamp ts;

	@ElementCollection
	private List<String> updatedFields;

	/**
	 * Constructs using an {@link Audited audited} instance.
	 * <br>
	 * An audited instances are supplied to the {@link Auditor#audit(Broker, Collection, Collection, Collection)
	 * auditor} by OpenJPA runtime within the transaction just before it is going to commit.
	 * <br>
	 * An audited instance carries the managed instance being audited in two <em>separate</em> references.
	 * The {link {@link Audited#getManagedObject()} first reference} is to the actual persistence instance
	 * being audited. The {link {@link Audited#getOriginalObject() second reference} is a <em>transient</em>
	 * copy of the actual persistence instance but in a state as it were when it entered the managed context
	 * i.e. when it was persisted or loaded from the database.
	 * <br>
	 * The {@link Audited} instance also knows the fields that were updated.
	 * @param a an audited instance.
	 */
	public AuditedEntry(Audited a) {
		audited = a.getManagedObject();
		ts = new Timestamp(new Date().getTime());
		operation = a.getType();
		if (operation == AuditableOperation.UPDATE) {
			updatedFields = Arrays.asList(a.getUpdatedFields());
		}

	}

	public Object getAudited() {
		return audited;
	}

	public AuditableOperation getOperation() {
		return operation;
	}

	public Timestamp getTimestamp() {
		return ts;
	}

	public long getId() {
		return id;
	}

	public List<String> getUpdatedFields() {
		return updatedFields;
	}
}
