package com.eactive.eai.adapter.socket2.common;

import com.eactive.eai.adapter.socket2.config.SocketLoggerManager;
import com.eactive.eai.common.util.Logger;
import org.apache.commons.collections.buffer.CircularFifoBuffer;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class CircularQueue extends CircularFifoBuffer {
	static final Logger logger = SocketLoggerManager.getInstance().getLogger();

	static final long AGE = 1000L * 60 * 60 * 24;   // 1 day
	static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("MM-dd HH:mm:ss");
	private String logPrefix = "CircularQueue | ";
	
	public CircularQueue(int maxSize) {
		super(maxSize);
	}
    
    @Override
    public synchronized boolean add(Object o) {
    	try {
    		return super.add(o);
    	} catch(Exception e) {
			super.clear();
    		logger.warn(logPrefix + e.getMessage());
    		return true;
    	}
    }
    
	public synchronized void addRecord(String recordData) {
    	try {
			super.add(new Tuple(System.currentTimeMillis(), recordData));
		} catch(Exception e) {
			super.clear();
			logger.warn(logPrefix + e.getMessage());
		}
	}
	
	public synchronized int getRecordCount() {
		clearOldRecords();
		return size();
	}

	public synchronized String[]getRecords() {
		clearOldRecords();
		
        Object[] elements = toArray();
        String[] errors = new String[elements.length];
    	for (int i=0; i<elements.length; i++) {
    		errors[i] = getDateFormat(((Tuple) elements[i]).getTime()) + ((Tuple) elements[i]).getMessage();
    	}
		return errors;
	}
	public String getDateFormat(long time){
		Instant instant = Instant.ofEpochMilli(time);
		ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
		return "["+dateFormat.format(zdt)+"] - ";
	}
	
	private synchronized void clearOldRecords() {
		try {
	        Object[] elements = toArray();
	    	for (int i=0; i<elements.length; i++) {
	    		Tuple tuple = (Tuple) elements[i];
	    		if (tuple != null && System.currentTimeMillis() - tuple.getTime() > AGE) {
	    			this.remove(tuple);
	    		}
	    	}
		} catch(Exception e) {
			super.clear();
			logger.warn(logPrefix + e.getMessage());
		}
	}
	
	public static class Tuple {
		long   time;
		String message;
		
		public Tuple(long time, String message) {
			this.time = time;
			this.message = message;
		}
		
		public long getTime() {
			return time;
		}
		
		public String getMessage() {
			return message;
		}
	}
	
    @Override
    public String toString() {
    	StringBuilder sb = new StringBuilder();
    	sb.append("CircularQueue max:" + maxSize() + " size:" + size() + "\n");
        sb.append("---------------------------------------------------------------------------------------------------------------------\n");
        Object[] elements = toArray();
    	for (int i=elements.length-1; i>=0; i--) {
    		if (elements[i] == null)
    			continue;
    		sb.append(((String) elements[i]) + "\n");
    	}
        sb.append("---------------------------------------------------------------------------------------------------------------------\n");
    	return sb.toString();
    }
}
