/*
 * Copyright 2000-2012 JetBrains s.r.o.
 *
 * 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 org.jetbrains.jps.javac;

import com.intellij.openapi.util.io.FileUtilRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.PathUtils;
import org.jetbrains.jps.incremental.BinaryContent;

import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import java.io.*;
import java.net.URI;

/**
 * @author Eugene Zhuravlev
 *         Date: 9/24/11
 */
public final class OutputFileObject extends SimpleJavaFileObject {
  @Nullable
  private final JavacFileManager.Context myContext;
  @Nullable
  private final File myOutputRoot;
  private final String myRelativePath;
  private final File myFile;
  @Nullable
  private final String myClassName;
  @Nullable private final URI mySourceUri;
  private volatile BinaryContent myContent;
  private final File mySourceFile;
  private final String myEncodingName;

  public OutputFileObject(@NotNull JavacFileManager.Context context,
                          @Nullable File outputRoot,
                          String relativePath,
                          @NotNull File file,
                          @NotNull Kind kind,
                          @Nullable String className,
                          @Nullable final URI sourceUri,
                          @Nullable final String encodingName) {
    this(context, outputRoot, relativePath, file, kind, className, sourceUri, encodingName, null);
  }

  public OutputFileObject(@Nullable JavacFileManager.Context context,
                          @Nullable File outputRoot,
                          String relativePath,
                          @NotNull File file,
                          @NotNull Kind kind,
                          @Nullable String className,
                          @Nullable final URI srcUri,
                          @Nullable final String encodingName, 
                          @Nullable BinaryContent content) {
    super(PathUtils.toURI(file.getPath()), kind);
    myContext = context;
    mySourceUri = srcUri;
    myContent = content;
    myOutputRoot = outputRoot;
    myRelativePath = relativePath;
    myFile = file;
    myClassName = className != null? className.replace('/', '.') : null;
    mySourceFile = srcUri != null? PathUtils.convertToFile(srcUri) : null;
    myEncodingName = encodingName;
  }

  @Nullable
  public File getOutputRoot() {
    return myOutputRoot;
  }

  public String getRelativePath() {
    return myRelativePath;
  }

  @NotNull
  public File getFile() {
    return myFile;
  }

  @Nullable
  public String getClassName() {
    return myClassName;
  }

  @Nullable
  public File getSourceFile() {
    return mySourceFile;
  }

  @Nullable
  public URI getSourceUri() {
    return mySourceUri;
  }

  @Override
  public ByteArrayOutputStream openOutputStream() {
    return new ByteArrayOutputStream() {
      @Override
      public void close() throws IOException {
        try {
          super.close();
        }
        finally {
          myContent = new BinaryContent(buf, 0, size());
          if (myContext != null) {
            myContext.consumeOutputFile(OutputFileObject.this);
          }
        }
      }
    };
  }

  @Override
  public InputStream openInputStream() throws IOException {
    final BinaryContent bytes = myContent;
    if (bytes != null) {
      return new ByteArrayInputStream(bytes.getBuffer(), bytes.getOffset(), bytes.getLength());
    }
    return new BufferedInputStream(new FileInputStream(myFile));
  }

  @Override
  public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    final BinaryContent content = myContent;
    if (content != null) {
      return new String(content.getBuffer(), content.getOffset(), content.getLength());
    }
    return FileUtilRt.loadFile(myFile, myEncodingName, false);
  }

  @Nullable
  public BinaryContent getContent() {
    return myContent;
  }

  public void updateContent(@NotNull byte[] updatedContent) {
    myContent = new BinaryContent(updatedContent, 0, updatedContent.length);
  }

  @Override
  public int hashCode() {
    return toUri().hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    return obj instanceof JavaFileObject && toUri().equals(((JavaFileObject)obj).toUri());
  }
}

@@ -873,63 +873,9 @@
 ols.
-JavaFileObject;%0Aimport javax.tools.SimpleJavaFileObject
+*
 ;%0Aim
@@ -4168,32 +4168,76 @@
 nt = myContent;%0A
+    final String encoding = myEncodingName;%0A
     if (content 
@@ -4256,24 +4256,56 @@
      return 
+encoding == null? %0A             
 new String(c
@@ -4357,32 +4357,132 @@
 ent.getLength())
+ : %0A             new String(content.getBuffer(), content.getOffset(), content.getLength(), encoding)
 ;%0A    %7D%0A    retu
@@ -4512,30 +4512,24 @@
 myFile, 
-myE
+e
 ncoding
-Name
 , false)

fix 'annotation processor-generated file saved in wrong encoding' problem (IDEA-167446)