/**
   * Initialises the given document with the given stream using the given encoding.
   *
   * @param document the document to be initialised
   * @param storage the storage which delivers the document content
   * @param encoding the character encoding for reading the given stream
   * @param monitor a progress monitor for cancellation, or <code>null</code>
   * @exception CoreException if the given storage can not be accessed or read
   */
  private static void setDocumentContent(
      SymbolisedDocument document, IStorage storage, String encoding, IProgressMonitor monitor)
      throws CoreException {
    Reader in = null;
    InputStream contentStream = new UnicodeInputStream(storage.getContents());
    try {

      final int DEFAULT_FILE_SIZE = 15 * 1024;

      if (encoding == null)
        in = new BufferedReader(new InputStreamReader(contentStream), DEFAULT_FILE_SIZE);
      else
        in = new BufferedReader(new InputStreamReader(contentStream, encoding), DEFAULT_FILE_SIZE);
      StringBuffer buffer = new StringBuffer(DEFAULT_FILE_SIZE);
      char[] readBuffer = new char[2048];
      int n = in.read(readBuffer);
      while (n > 0) {
        if (monitor != null && monitor.isCanceled()) return;

        buffer.append(readBuffer, 0, n);
        n = in.read(readBuffer);
      }

      document.set(buffer.toString());

    } catch (IOException x) {
      throw new CoreException(
          new Status(
              IStatus.ERROR,
              EditorsUI.PLUGIN_ID,
              IStatus.OK,
              "Failed to access or read underlying storage",
              x)); //$NON-NLS-1$
    } finally {
      try {
        if (in != null) in.close();
        else contentStream.close();
      } catch (IOException x) {
        // ignore
      }
    }
  }
  /**
   * Reads in the saved document into <code>fReference</code>.
   *
   * @param monitor a progress monitor, or <code>null</code>
   * @param force <code>true</code> if the reference document should also be read if the current
   *     document is <code>null</code>,<code>false</code> if it should only be updated if it already
   *     existed.
   */
  private void readDocument(IProgressMonitor monitor, boolean force) {

    // protect against concurrent disposal
    IDocumentProvider prov = fDocumentProvider;
    IEditorInput inp = fEditorInput;
    SymbolisedDocument doc = fReference;
    ITextEditor editor = fEditor;

    if (prov instanceof IStorageDocumentProvider && inp instanceof IStorageEditorInput) {

      IStorageEditorInput input = (IStorageEditorInput) inp;
      IStorageDocumentProvider provider = (IStorageDocumentProvider) prov;

      if (doc == null) {
        if (force || fDocumentRead) doc = new SymbolisedDocument();
        else return;
      } else {
        doc.syncSymbolSupport();
      }

      IJobManager jobMgr = Job.getJobManager(); // Platform.getJobManager();

      try {
        IStorage storage = input.getStorage();
        // check for null for backward compatibility (we used to check before...)
        if (storage == null) return;
        fProgressMonitor = monitor;
        ISchedulingRule rule = getSchedulingRule(storage);

        // this protects others from not being able to delete the file,
        // and protects ourselves from concurrent access to fReference
        // (in the case there already is a valid fReference)

        // one might argue that this rule should already be in the Job
        // description we're running in, however:
        // 1) we don't mind waiting for someone else here
        // 2) we do not take long, or require other locks etc. -> short
        // delay for any other job requiring the lock on file
        try {
          lockDocument(monitor, jobMgr, rule);

          String encoding;
          if (storage instanceof IEncodedStorage)
            encoding = ((IEncodedStorage) storage).getCharset();
          else encoding = null;

          LastSaveReferenceProvider.setDocumentContent(doc, storage, encoding, monitor);
        } finally {
          unlockDocument(jobMgr, rule);
          fProgressMonitor = null;
        }

      } catch (CoreException e) {
        return;
      }

      if (monitor != null && monitor.isCanceled()) return;

      // update state
      synchronized (fLock) {
        if (fDocumentProvider == provider && fEditorInput == input) {
          // only update state if our provider / input pair has not
          // been updated in between (dispose or setActiveEditor)
          fReference = doc;
          fDocumentRead = true;
          addElementStateListener(editor, prov);
        }
      }
    }
  }