/*
 * 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.linker;

import com.google.gwt.core.ext.LinkerContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.AbstractLinker;
import com.google.gwt.core.ext.linker.Artifact;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.CompilationResult;
import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.Shardable;
import com.google.gwt.core.ext.linker.SoftPermutation;
import com.google.gwt.core.ext.linker.SymbolData;
import com.google.gwt.core.ext.linker.SyntheticArtifact;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.collect.HashMap;
import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import com.google.gwt.thirdparty.debugging.sourcemap.SourceMapGeneratorV3;
import com.google.gwt.thirdparty.debugging.sourcemap.SourceMapGeneratorV3.ExtensionMergeAction;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.regex.Pattern;

/**
 * This Linker exports the symbol maps associated with each compilation result as a private file.
 * The names of the symbol maps files are computed by appending {@value #STRONG_NAME_SUFFIX} to the
 * value returned by {@link CompilationResult#getStrongName()}.
 */
@LinkerOrder(Order.POST)
@Shardable
public class SymbolMapsLinker extends AbstractLinker {

  public static final String MAKE_SYMBOL_MAPS = "compiler.useSymbolMaps";

  /**
   * Artifact to record insertions or deletions made to Javascript fragments.
   */
  public static class ScriptFragmentEditsArtifact extends Artifact<ScriptFragmentEditsArtifact> {

    /**
     * Operation type performed on script.
     */
    public enum Edit {
      PREFIX, INSERT, REMOVE
    }

    private static class EditOperation {

      public static EditOperation prefix(String data) {
        return new EditOperation(Edit.PREFIX, 0, data);
      }

      Edit op;
      int numLines;

      public EditOperation(
          Edit op, int lineNumber, String data) {
        this.op = op;
        this.numLines = countNewLines(data);
      }

      public int getNumLines() {
        return numLines;
      }

      public Edit getOp() {
        return op;
      }

      private int countNewLines(String chunkJs) {
        int newLineCount = 0;
        for (int j = 0; j < chunkJs.length(); j++) {
          if (chunkJs.charAt(j) == '\n') {
            newLineCount++;
          }
        }
        return newLineCount;
      }
    }

    private List<EditOperation> editOperations = new ArrayList<EditOperation>();

    private String strongName;
    private int fragment;

    public ScriptFragmentEditsArtifact(String strongName,
        int fragment) {
      super(SymbolMapsLinker.class);
      this.strongName = strongName;
      this.fragment = fragment;
    }

    public int getFragment() {
      return fragment;
    }

    public String getStrongName() {
      return strongName;
    }

    @Override
    public int hashCode() {
      return (strongName + fragment).hashCode();
    }

    public void prefixLines(String lines) {
      editOperations.add(EditOperation.prefix(lines));
    }

    @Override
    protected int compareToComparableArtifact(SymbolMapsLinker.ScriptFragmentEditsArtifact o) {
      int result = (strongName + fragment).compareTo(strongName + fragment);
      return result;
    }

    @Override
    protected Class<ScriptFragmentEditsArtifact> getComparableArtifactType() {
      return ScriptFragmentEditsArtifact.class;
    }
  }

  /**
   * Artifact to represent a sourcemap file to be processed by SymbolMapsLinker.
   */
  public static class SourceMapArtifact extends SyntheticArtifact {

    // This pattern should match sourceMapFilenameForFragment.
    public static final Pattern isSourceMapFile = Pattern.compile("sourceMap[0-9]+\\.json$");

    private int permutationId;
    private int fragment;
    private byte[] js;

    private final String sourceRoot;

    public SourceMapArtifact(int permutationId, int fragment, byte[] js, String sourceRoot) {
      super(SymbolMapsLinker.class, permutationId + '/' + sourceMapFilenameForFragment(fragment), js);
      this.permutationId = permutationId;
      this.fragment = fragment;
      this.js = js;
      this.sourceRoot = sourceRoot;
    }

    public int getFragment() {
      return fragment;
    }

    public int getPermutationId() {
      return permutationId;
    }

    /**
     * The base URL for Java filenames in the sourcemap.
     * (We need to reapply this after edits.)
     */
    public String getSourceRoot() {
      return sourceRoot;
    }

    public static String sourceMapFilenameForFragment(int fragment) {
      // If this changes, update isSourceMapFile.
      return "sourceMap" + fragment + ".json";
    }
  }

  /**
   * This value is appended to the strong name of the CompilationResult to form the symbol map's
   * filename.
   */
  public static final String STRONG_NAME_SUFFIX = ".symbolMap";

  public static String propertyMapToString(
      Map<SelectionProperty, String> propertyMap) {
    StringWriter writer = new StringWriter();
    PrintWriter pw = new PrintWriter(writer);
    printPropertyMap(pw, propertyMap);
    pw.flush();
    return writer.toString();
  }

  private static void printPropertyMap(PrintWriter pw,
      Map<SelectionProperty, String> map) {
    boolean needsComma = false;
    for (Map.Entry<SelectionProperty, String> entry : map.entrySet()) {
      if (needsComma) {
        pw.print(" , ");
      } else {
        needsComma = true;
      }

      pw.print("'");
      pw.print(entry.getKey().getName());
      pw.print("' : '");
      pw.print(entry.getValue());
      pw.print("'");
    }
  }

  @Override
  public String getDescription() {
    return "Export CompilationResult symbol maps";
  }

  /**
   * Included to support legacy non-shardable subclasses.
   */
  @Override
  public ArtifactSet link(TreeLogger logger, LinkerContext context,
      ArtifactSet artifacts) throws UnableToCompleteException {
    return link(logger, context, artifacts, true);
  }

  @Override
  public ArtifactSet link(TreeLogger logger, LinkerContext context,
      ArtifactSet artifacts, boolean onePermutation)
      throws UnableToCompleteException {

    if (onePermutation) {
      artifacts = new ArtifactSet(artifacts);
      Map<Integer, String> permMap = new HashMap<Integer, String>();

      Event writeSymbolMapsEvent =
          SpeedTracerLogger.start(CompilerEventType.WRITE_SYMBOL_MAPS);
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      for (CompilationResult result : artifacts.find(CompilationResult.class)) {

        boolean makeSymbolMaps = true;

        for (SoftPermutation perm : result.getSoftPermutations()) {
          for (Entry<SelectionProperty, String> propMapEntry : perm.getPropertyMap().entrySet()) {
            if (propMapEntry.getKey().getName().equals(MAKE_SYMBOL_MAPS)) {
              makeSymbolMaps = Boolean.valueOf(propMapEntry.getValue());
            }
          }
        }

        permMap.put(result.getPermutationId(), result.getStrongName());

        if (makeSymbolMaps) {
          PrintWriter pw = new PrintWriter(out);
          doWriteSymbolMap(logger, result, pw);
          pw.close();

          doEmitSymbolMap(logger, artifacts, result, out);
          out.reset();
        }
      }
      writeSymbolMapsEvent.end();

      Event writeSourceMapsEvent =
          SpeedTracerLogger.start(CompilerEventType.WRITE_SOURCE_MAPS);
      for (SourceMapArtifact se : artifacts.find(SourceMapArtifact.class)) {
        // filename is permutation_id/sourceMap<fragmentNumber>.json
        String sourceMapString = Util.readStreamAsString(se.getContents(logger));
        String strongName = permMap.get(se.getPermutationId());
        String partialPath = strongName + "_sourceMap" + se.getFragment() + ".json";

        int fragment = se.getFragment();
        ScriptFragmentEditsArtifact editArtifact = null;
        for (ScriptFragmentEditsArtifact mp : artifacts.find(ScriptFragmentEditsArtifact.class)) {
          if (mp.getStrongName().equals(strongName) && mp.getFragment() == fragment) {
            editArtifact = mp;
            artifacts.remove(editArtifact);
            break;
          }
        }

        SyntheticArtifact emArt = null;
        // no need to adjust source map
        if (editArtifact == null) {
          emArt = emitSourceMapString(logger, sourceMapString, partialPath);
        } else {
          SourceMapGeneratorV3 sourceMapGenerator = new SourceMapGeneratorV3();

          if (se.getSourceRoot() != null) {
            // Reapply source root since mergeMapSection() will not copy it.
            sourceMapGenerator.setSourceRoot(se.getSourceRoot());
          }

          try {
            int totalPrefixLines = 0;
            for (ScriptFragmentEditsArtifact.EditOperation op : editArtifact.editOperations) {
              if (op.getOp() == ScriptFragmentEditsArtifact.Edit.PREFIX) {
                totalPrefixLines += op.getNumLines();
              }
            }
            // TODO(cromwellian): apply insert and remove edits
            sourceMapGenerator.mergeMapSection(totalPrefixLines, 0, sourceMapString,
                new ExtensionMergeAction() {
                  @Override
                  public Object merge(String extKey, Object oldVal, Object newVal) {
                    return newVal;
                  }
                });
            StringWriter stringWriter = new StringWriter();
            sourceMapGenerator.appendTo(stringWriter, "sourceMap");
            emArt = emitSourceMapString(logger, stringWriter.toString(), partialPath);
          } catch (Exception e) {
            logger.log(TreeLogger.Type.WARN, "Can't write source map " + partialPath, e);
          }
        }
        artifacts.add(emArt);
        artifacts.remove(se);
      }
      writeSourceMapsEvent.end();
    }
    return artifacts;
  }

  /**
   * Override to change the manner in which the symbol map is emitted.
   */
  protected void doEmitSymbolMap(TreeLogger logger, ArtifactSet artifacts,
      CompilationResult result, ByteArrayOutputStream out)
      throws UnableToCompleteException {
    EmittedArtifact symbolMapArtifact = emitBytes(logger, out.toByteArray(),
        result.getStrongName() + STRONG_NAME_SUFFIX);
    // TODO: change to Deploy when possible
    symbolMapArtifact.setVisibility(Visibility.LegacyDeploy);
    artifacts.add(symbolMapArtifact);
  }

  /**
   * Override to change the format of the symbol map.
   *
   * @param logger the logger to write to
   * @param result the compilation result
   * @param pw     the output PrintWriter
   * @throws UnableToCompleteException if an error occurs
   */
  protected void doWriteSymbolMap(TreeLogger logger, CompilationResult result,
      PrintWriter pw) throws UnableToCompleteException {
    pw.println("# { " + result.getPermutationId() + " }");

    for (SortedMap<SelectionProperty, String> map : result.getPropertyMap()) {
      pw.print("# { ");
      printPropertyMap(pw, map);
      pw.println(" }");
    }

    pw.println("# jsName, jsniIdent, className, memberName, sourceUri, sourceLine, fragmentNumber");
    StringBuilder sb = new StringBuilder(1024);
    char[] buf = new char[1024];
    for (SymbolData symbol : result.getSymbolMap()) {
      sb.append(symbol.getSymbolName());

      sb.append(',');
      String jsniIdent = symbol.getJsniIdent();
      if (jsniIdent != null) {
        sb.append(jsniIdent);
      }
      sb.append(',');
      sb.append(symbol.getClassName());
      sb.append(',');
      String memberName = symbol.getMemberName();
      if (memberName != null) {
        sb.append(memberName);
      }
      sb.append(',');
      String sourceUri = symbol.getSourceUri();
      if (sourceUri != null) {
        sb.append(sourceUri);
      }
      sb.append(',');
      sb.append(symbol.getSourceLine());
      sb.append(',');
      sb.append(symbol.getFragmentNumber());
      sb.append('\n');

      int sbLen = sb.length();
      if (buf.length < sbLen) {
        int bufLen = buf.length;
        while (bufLen < sbLen) {
          bufLen <<= 1;
        }
        buf = new char[bufLen];
      }
      sb.getChars(0, sbLen, buf, 0);
      pw.write(buf, 0, sbLen);
      sb.setLength(0);
    }
  }

  protected SyntheticArtifact emitSourceMapString(TreeLogger logger, String contents,
      String partialPath) throws UnableToCompleteException {
    SyntheticArtifact emArt = emitString(logger, contents, partialPath);
    emArt.setVisibility(Visibility.LegacyDeploy);
    return emArt;
  }
}
