/*
 * Copyright 2009 Google Inc.
 * 
 * Licensed 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 com.google.gwt.core.ext.soyc.impl;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.soyc.ClassMember;
import com.google.gwt.core.ext.soyc.FunctionMember;
import com.google.gwt.core.ext.soyc.Member;
import com.google.gwt.core.ext.soyc.Range;
import com.google.gwt.core.ext.soyc.Story;
import com.google.gwt.core.ext.soyc.Story.Origin;
import com.google.gwt.dev.jjs.Correlation;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.Correlation.Axis;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.js.ast.JsFunction;
import com.google.gwt.dev.util.Util;
import com.google.gwt.util.tools.Utility;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.TreeSet;
import java.util.zip.GZIPOutputStream;

/**
 * Records {@link Story}s to a file for Compile Reports.
 */
public class StoryRecorder {

  /**
   * Associates a SourceInfo with a Range.
   */
  private static class RangeInfo {
    public final SourceInfo info;
    public final Range range;

    public RangeInfo(Range range, SourceInfo info) {
      assert range != null;
      assert info != null;
      this.range = range;
      this.info = info;
    }
  }

  private static final int MAX_STRING_BUILDER_SIZE = 65536;

  /**
   * Used to record dependencies of a program.
   */
  public static void recordStories(TreeLogger logger, OutputStream out,
      List<Map<Range, SourceInfo>> sourceInfoMaps, String[] js) {
    new StoryRecorder().recordStoriesImpl(logger, out, sourceInfoMaps, js);
  }

  private StringBuilder builder;

  private int curHighestFragment = 0;

  private OutputStream gzipStream;
  
  private String[] js;

  /**
   * Used by {@link #popAndRecord(Stack)} to determine start and end ranges.
   */
  private int lastEnd = 0;

  /**
   * This is a class field for convenience, but it should be deleted at the end
   * of the constructor.
   */
  private transient Map<Correlation, Member> membersByCorrelation = new IdentityHashMap<Correlation, Member>();
  
  /**
   * This is a class field for convenience, but it should be deleted at the end
   * of the constructor.
   */
  private transient Map<SourceInfo, StoryImpl> storyCache = new IdentityHashMap<SourceInfo, StoryImpl>();
  private Map<Story, Integer> storyIds = new HashMap<Story, Integer>();

  private StoryRecorder() {
  }
  
  protected void recordStoriesImpl(TreeLogger logger, OutputStream out,
      List<Map<Range, SourceInfo>> sourceInfoMaps, String[] js) {

    logger = logger.branch(TreeLogger.INFO, "Creating Stories file for the compile report");

    this.js = js;

    try {
      builder = new StringBuilder(MAX_STRING_BUILDER_SIZE * 2);
      gzipStream = new GZIPOutputStream(out);

      /*
       * Don't retain beyond the constructor to avoid lingering references to
       * AST nodes.
       */
      MemberFactory memberFactory = new MemberFactory();

      // Record what we've seen so far
      TreeSet<ClassMember> classesMutable = new TreeSet<ClassMember>(
          Member.SOURCE_NAME_COMPARATOR);
      TreeSet<FunctionMember> functionsMutable = new TreeSet<FunctionMember>(
          Member.SOURCE_NAME_COMPARATOR);
      Set<SourceInfo> sourceInfoSeen = new HashSet<SourceInfo>();

      builder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soyc>\n<stories>\n");

      int fragment = 0;
      for (Map<Range, SourceInfo> sourceInfoMap : sourceInfoMaps) {
        lastEnd = 0;
        analyzeFragment(memberFactory, classesMutable, functionsMutable,
            sourceInfoMap, sourceInfoSeen, fragment++);
        
        // Flush output to improve memory locality
        flushOutput();
      }

      builder.append("</stories>\n</soyc>\n");

      /*
       * Clear the member fields that we don't need anymore to allow GC of the
       * SourceInfo objects
       */
      membersByCorrelation = null;
      storyCache = null;

      Util.writeUtf8(builder, gzipStream);
      Utility.close(gzipStream);

      logger.log(TreeLogger.INFO, "Done");
    } catch (Throwable e) {
      logger.log(TreeLogger.ERROR, "Could not write dependency file.", e);
    }
  }
  
  private void analyzeFragment(MemberFactory memberFactory,
      TreeSet<ClassMember> classesMutable,
      TreeSet<FunctionMember> functionsMutable,
      Map<Range, SourceInfo> sourceInfoMap, Set<SourceInfo> sourceInfoSeen,
      int fragment) throws IOException {
    /*
     * We want to iterate over the Ranges so that enclosing Ranges come before
     * their enclosed Ranges...
     */
    Range[] dependencyOrder = sourceInfoMap.keySet().toArray(
        new Range[sourceInfoMap.size()]);
    Arrays.sort(dependencyOrder, Range.DEPENDENCY_ORDER_COMPARATOR);

    Stack<RangeInfo> dependencyScope = new Stack<RangeInfo>();
    for (Range range : dependencyOrder) {
      SourceInfo info = sourceInfoMap.get(range);
      assert info != null;

      // Infer dependency information
      if (!dependencyScope.isEmpty()) {

        /*
         * Pop frames until we get back to a container, using this as a chance
         * to build up our list of non-overlapping Ranges to report back to the
         * user.
         */
        while (!dependencyScope.peek().range.contains(range)) {
          popAndRecord(dependencyScope, fragment);
        }
      }

      // Possibly create and record Members
      if (!sourceInfoSeen.contains(info)) {
        sourceInfoSeen.add(info);
        for (Correlation c : info.getPrimaryCorrelationsArray()) {
          if (c == null) {
            continue;
          }
          if (membersByCorrelation.containsKey(c)) {
            continue;
          }

          switch (c.getAxis()) {
            case CLASS: {
              JDeclaredType type = c.getType();
              StandardClassMember member = memberFactory.get(type);
              membersByCorrelation.put(c, member);
              classesMutable.add(member);
              break;
            }
            case FIELD: {
              JField field = c.getField();
              JDeclaredType type = c.getType();
              StandardFieldMember member = memberFactory.get(field);
              memberFactory.get(type).addField(member);
              membersByCorrelation.put(c, member);
              break;
            }
            case FUNCTION: {
              JsFunction function = c.getFunction();
              StandardFunctionMember member = memberFactory.get(function);
              membersByCorrelation.put(c, member);
              functionsMutable.add(member);
              break;
            }
            case METHOD: {
              JMethod method = c.getMethod();
              JDeclaredType type = c.getType();
              StandardMethodMember member = memberFactory.get(method);
              memberFactory.get(type).addMethod(member);
              membersByCorrelation.put(c, member);
              break;
            }
          }
        }
      }

      dependencyScope.push(new RangeInfo(range, info));
    }

    // Unwind the rest of the stack to finish out the ranges
    while (!dependencyScope.isEmpty()) {
      popAndRecord(dependencyScope, fragment);
    }

    /*
     * Because the first Range corresponds to the SourceInfo of the whole
     * program, we'll know that we got all of the data if the ends match up. If
     * this assert passes, we know that we've correctly generated a sequence of
     * non-overlapping Ranges that encompass the whole program.
     */
    assert dependencyOrder[0].getEnd() == lastEnd;
  }

  private void emitStory(StoryImpl story, Range range) throws IOException {
    int storyNum;
    if (storyIds.containsKey(story)) {
      storyNum = storyIds.get(story);
    } else {
      storyNum = storyIds.size();
      storyIds.put(story, storyNum);
    }

    builder.append("<story id=\"story");
    builder.append(storyNum);
    if (story.getLiteralTypeName() != null) {
      builder.append("\" literal=\"");
      builder.append(story.getLiteralTypeName());
    }
    builder.append("\">\n");

    Set<Origin> origins = story.getSourceOrigin();
    if (origins.size() > 0) {
      builder.append("<origins>\n");
      for (Origin origin : origins) {
        builder.append("<origin lineNumber=\"");
        builder.append(origin.getLineNumber());
        builder.append("\" location=\"");
        builder.append(origin.getLocation());
        builder.append("\"/>\n");
        
        flushOutput();
      }
      builder.append("</origins>\n");
    }

    Set<Member> correlations = story.getMembers();
    if (correlations.size() > 0) {
      builder.append("<correlations>\n");
      for (Member correlation : correlations) {
        builder.append("<by idref=\"");
        builder.append(correlation.getSourceName());
        builder.append("\"/>\n");
        
        flushOutput();
      }
      builder.append("</correlations>\n");
    }

    builder.append("<js fragment=\"");
    builder.append(curHighestFragment);
    builder.append("\"/>\n<storyref idref=\"story");
    builder.append(storyNum);

    int start = range.getStart();
    int end = range.getEnd();
    String jsCode = js[curHighestFragment];
    if ((start == end) || ((end == start + 1) && jsCode.charAt(start) == '\n')) {
      builder.append("\"/>\n</story>\n");
    } else {
      builder.append("\">");
      SizeMapRecorder.escapeXml(jsCode, start, end, false, builder);
      builder.append("</storyref>\n</story>\n");
    }
  }

  private void flushOutput() throws IOException {
    // Flush output to improve memory locality
    if (builder.length() > MAX_STRING_BUILDER_SIZE) {
      Util.writeUtf8(builder, gzipStream);
      builder.setLength(0);
    }
  }

  /**
   * Remove an element from the RangeInfo stack and stare a new StoryImpl with
   * the right length, possibly sub-dividing the super-enclosing Range in the
   * process.
   */
  private void popAndRecord(Stack<RangeInfo> dependencyScope, int fragment)
      throws IOException {
    RangeInfo rangeInfo = dependencyScope.pop();
    Range toStore = rangeInfo.range;

    /*
     * Make a new Range for the gap between the popped Range and whatever we
     * last stored.
     */
    if (lastEnd < toStore.getStart()) {
      Range newRange = new Range(lastEnd, toStore.getStart());
      assert !dependencyScope.isEmpty();

      SourceInfo gapInfo = dependencyScope.peek().info;
      recordStory(gapInfo, fragment, newRange.length(), newRange);

      lastEnd += newRange.length();
    }

    /*
     * Store as much of the current Range as we haven't previously stored. The
     * Max.max() is there to take care of the tail end of Ranges that have had a
     * sub-range previously stored.
     */
    if (lastEnd < toStore.getEnd()) {
      Range newRange = new Range(Math.max(lastEnd, toStore.getStart()),
          toStore.getEnd());
      recordStory(rangeInfo.info, fragment, newRange.length(), newRange);
      lastEnd += newRange.length();
    }
  }

  private void recordStory(SourceInfo info, int fragment, int length,
      Range range) throws IOException {
    assert info != null;
    assert storyCache != null;

    if (fragment > curHighestFragment) {
      curHighestFragment = fragment;
    }

    StoryImpl theStory;
    if (!storyCache.containsKey(info)) {
      SortedSet<Member> members = new TreeSet<Member>(
          Member.TYPE_AND_SOURCE_NAME_COMPARATOR);
      Set<Origin> origins = new HashSet<Origin>();

      for (Correlation c : info.getAllCorrelations()) {
        Member m = membersByCorrelation.get(c);
        if (m != null) {
          members.add(m);
        }
        
        if (c.getAxis() == Axis.ORIGIN) {
          origins.add(new OriginImpl(c.getOrigin()));
        }
      }

      String literalType = null;
      Correlation literalCorrelation = info.getPrimaryCorrelation(Axis.LITERAL);
      if (literalCorrelation != null) {
        literalType = literalCorrelation.getLiteral().getDescription();
      }

      theStory = new StoryImpl(storyCache.size(), members, origins,
          literalType, fragment, length);
      storyCache.put(info, theStory);
    } else {
      // Use a copy-constructed instance
      theStory = new StoryImpl(storyCache.get(info), length);
    }

    emitStory(theStory, range);
  }

}
