// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library services.src.index.store.codec;

import 'dart:collection';

import 'package:analysis_server/analysis/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';

/**
 * A helper that encodes/decodes [AnalysisContext]s from/to integers.
 */
class ContextCodec {
  /**
   * A table mapping contexts to their unique indices.
   */
  Map<AnalysisContext, int> _contextToIndex =
      new HashMap<AnalysisContext, int>();

  /**
   * A table mapping indices to the corresponding contexts.
   */
  Map<int, AnalysisContext> _indexToContext =
      new HashMap<int, AnalysisContext>();

  /**
   * The next id to assign.
   */
  int _nextId = 0;

  /**
   * Returns the [AnalysisContext] that corresponds to the given index.
   */
  AnalysisContext decode(int index) => _indexToContext[index];

  /**
   * Returns an unique index for the given [AnalysisContext].
   */
  int encode(AnalysisContext context) {
    int index = _contextToIndex[context];
    if (index == null) {
      index = _nextId++;
      _contextToIndex[context] = index;
      _indexToContext[index] = context;
    }
    return index;
  }

  /**
   * Removes the given [context].
   */
  void remove(AnalysisContext context) {
    int id = _contextToIndex.remove(context);
    if (id != null) {
      _indexToContext.remove(id);
    }
  }
}

/**
 * A helper that encodes/decodes [IndexableObject]s to/from integers.
 */
class ElementCodec {
  // TODO(brianwilkerson) Rename this class now that if encodes indexable
  // objects rather than elements.
  final StringCodec _stringCodec;

  ElementCodec(this._stringCodec);

  /**
   * Returns an [IndexableObject] that corresponds to the given identifiers.
   */
  IndexableObject decode(
      AnalysisContext context, int fileId, int offset, int kindId) {
    IndexableObjectKind kind = IndexableObjectKind.getKind(kindId);
    if (kind == null) {
      return null;
    } else if (kind is IndexableNameKind) {
      String name = _stringCodec.decode(offset);
      return new IndexableName(name);
    }
    String filePath = _stringCodec.decode(fileId);
    return kind.decode(context, filePath, offset);
  }

  /**
   * Returns the first component of the [indexable] id.
   * In the most cases it is an encoding of the [indexable]'s file path.
   * If the given [indexable] is not defined in a file, returns `-1`.
   */
  int encode1(IndexableObject indexable) {
    Source source = indexable.source;
    if (source == null) {
      return -1;
    }
    String filePath = source.fullName;
    return _stringCodec.encode(filePath);
  }

  /**
   * Returns the second component of the [indexable] id.
   * In the most cases it is the [indexable]'s name offset.
   */
  int encode2(IndexableObject indexable) {
    if (indexable is IndexableName) {
      String name = indexable.name;
      return _stringCodec.encode(name);
    }
    return indexable.offset;
  }

  /**
   * Returns the third component of the [indexable] id.
   * In the most cases it is the [indexable]'s kind.
   */
  int encode3(IndexableObject indexable) {
    return indexable.kind.index;
  }

  /**
   * Returns an integer that corresponds to the name of [indexable].
   */
  int encodeHash(IndexableObject indexable) {
    return indexable.kind.encodeHash(_stringCodec.encode, indexable);
  }
}

/**
 * A helper that encodes/decodes [Relationship]s to/from integers.
 */
class RelationshipCodec {
  final StringCodec _stringCodec;

  RelationshipCodec(this._stringCodec);

  RelationshipImpl decode(int idIndex) {
    String id = _stringCodec.decode(idIndex);
    return RelationshipImpl.getRelationship(id);
  }

  int encode(RelationshipImpl relationship) {
    String id = relationship.identifier;
    return _stringCodec.encode(id);
  }
}

/**
 * A helper that encodes/decodes [String]s from/to integers.
 */
class StringCodec {
  /**
   * A table mapping names to their unique indices.
   */
  final Map<String, int> nameToIndex = new HashMap<String, int>();

  /**
   * A table mapping indices to the corresponding strings.
   */
  final List<String> _indexToName = <String>[];

  /**
   * Returns the [String] that corresponds to the given index.
   */
  String decode(int index) => _indexToName[index];

  /**
   * Returns an unique index for the given [String].
   */
  int encode(String name) {
    int index = nameToIndex[name];
    if (index == null) {
      index = _indexToName.length;
      nameToIndex[name] = index;
      _indexToName.add(name);
    }
    return index;
  }
}
