/*
 * 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.log4j.chainsaw;

import java.awt.Color;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.helpers.Constants;
import org.apache.log4j.rule.Rule;
import org.apache.log4j.spi.LoggingEvent;

/**
 * Wrap access to a LoggingEvent.  All property updates need to go through this object and not through the wrapped logging event,
 * since the properties are shared by two views of the same backing LoggingEvent, and loggingEvent itself creates a copy of passed-in properties..
 *
 * Property reads can be made on the actual LoggingEvent.
 */
public class LoggingEventWrapper {
  private final LoggingEvent loggingEvent;
  private static final int DEFAULT_HEIGHT = -1;

  private Color colorRuleBackground = ChainsawConstants.COLOR_DEFAULT_BACKGROUND;
  private Color colorRuleForeground = ChainsawConstants.COLOR_DEFAULT_FOREGROUND;
  private int markerHeight = DEFAULT_HEIGHT;
  private int msgHeight = DEFAULT_HEIGHT;

  //set to the log4jid value via setId - assumed to never change
  private int id;

  private boolean searchMatch = false;
  //a Map of event fields to Sets of string matches (can be used to render matches differently)
  Map eventMatches = new HashMap();
  private LoggingEventWrapper syncWrapper;
  private boolean displayed;

  public LoggingEventWrapper(LoggingEvent loggingEvent) {
    this.loggingEvent = loggingEvent;
  }

  public LoggingEventWrapper(LoggingEventWrapper loggingEventWrapper) {
    this.loggingEvent = loggingEventWrapper.getLoggingEvent();
    this.id = loggingEventWrapper.id;
    this.syncWrapper = loggingEventWrapper;
    loggingEventWrapper.syncWrapper = this;
  }

  public LoggingEvent getLoggingEvent() {
    return loggingEvent;
  }

  public void setProperty(String propName, String propValue) {
    loggingEvent.setProperty(propName, propValue);
    if (id == 0) {
      if (propName.equals(Constants.LOG4J_ID_KEY)) {
        id = Integer.parseInt(propValue);
      }
    }
    if (syncWrapper != null && !propName.equals(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE)) {
      syncWrapper.getLoggingEvent().setProperty(propName, propValue);
    }
  }

  public Object removeProperty(String propName) {
    Object result = loggingEvent.removeProperty(propName);
    if (syncWrapper != null && !propName.equals(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE)) {
      syncWrapper.getLoggingEvent().removeProperty(propName);
    }
    return result;
  }

  public Set getPropertyKeySet() {
    return loggingEvent.getPropertyKeySet();
  }

  public void updateColorRuleColors(Color backgroundColor, Color foregroundColor) {
    if (backgroundColor != null && foregroundColor != null) {
      this.colorRuleBackground = backgroundColor;
      this.colorRuleForeground = foregroundColor;
      if (syncWrapper != null) {
        syncWrapper.colorRuleBackground = this.colorRuleBackground;
        syncWrapper.colorRuleForeground = this.colorRuleForeground;
      }
    } else {
      this.colorRuleBackground = ChainsawConstants.COLOR_DEFAULT_BACKGROUND;
      this.colorRuleForeground = ChainsawConstants.COLOR_DEFAULT_FOREGROUND;
      if (syncWrapper != null) {
        syncWrapper.colorRuleBackground = this.colorRuleBackground;
        syncWrapper.colorRuleForeground = this.colorRuleForeground;
      }
    }
  }

  public void evaluateSearchRule(Rule searchRule) {
    eventMatches.clear();
    searchMatch = searchRule != null && searchRule.evaluate(loggingEvent, eventMatches);
  }

  public Map getSearchMatches() {
    return eventMatches;
  }

  public Color getForeground() {
    return colorRuleForeground;
  }

  public Color getBackground() {
    return colorRuleBackground;
  }

  public Color getColorRuleBackground() {
    return colorRuleBackground;
  }

  public Color getColorRuleForeground() {
    return colorRuleForeground;
  }

  public boolean isSearchMatch() {
    return searchMatch;
  }

  public void setMarkerHeight(int markerHeight) {
    this.markerHeight = markerHeight;
  }

  public int getMarkerHeight() {
    return markerHeight;
  }

  public void setMsgHeight(int msgHeight) {
    this.msgHeight = msgHeight;
  }

  public int getMsgHeight() {
    return msgHeight;
  }

  public void setDisplayed(boolean b) {
    markerHeight = DEFAULT_HEIGHT;
    msgHeight = DEFAULT_HEIGHT;
    displayed = b;
  }

  public void setPreviousDisplayedEventTimestamp(long previousDisplayedEventTimeStamp) {
    setProperty(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE, String.valueOf(loggingEvent.getTimeStamp() - previousDisplayedEventTimeStamp));
  }

  public boolean isDisplayed() {
    return displayed;
  }

  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    LoggingEventWrapper that = (LoggingEventWrapper) o;

    if (id != that.id) {
      return false;
    }

    return true;
  }

  public int hashCode() {
    return id;
  }

  public String toString() {
    return "LoggingEventWrapper - id: " + id + " background: " + getBackground() + ", foreground: " + getForeground() + ", msg: " + loggingEvent.getMessage();
  }
}
