// Copyright (c) 2019, 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.

import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:html/dom.dart';
import 'package:html/parser.dart' show parseFragment;
import 'package:source_span/source_span.dart';

import 'manifest_values.dart';
import 'manifest_warning_code.dart';

class ManifestValidator {
  /**
   * The source representing the file being validated.
   */
  final Source source;

  /**
   * Initialize a newly create validator to validate the content of the given
   * [source].
   */
  ManifestValidator(this.source);

  /*
   * Validate the [contents] of the Android Manifest file.
   */
  List<AnalysisError> validate(String contents, bool checkManifest) {
    RecordingErrorListener recorder = new RecordingErrorListener();
    ErrorReporter reporter = new ErrorReporter(recorder, source);

    if (checkManifest) {
      var document =
          parseFragment(contents, container: MANIFEST_TAG, generateSpans: true);
      var manifest = document.children.firstWhere(
          (element) => element.localName == MANIFEST_TAG,
          orElse: () => null);
      var features = manifest?.getElementsByTagName(USES_FEATURE_TAG) ?? [];
      var permissions =
          manifest?.getElementsByTagName(USES_PERMISSION_TAG) ?? [];
      var activities = _findActivityElements(manifest);

      _validateTouchScreenFeature(features, manifest, reporter);
      _validateFeatures(features, reporter);
      _validatePermissions(permissions, features, reporter);
      _validateActivities(activities, reporter);
    }
    return recorder.errors;
  }

  /*
   * Validate the presence/absence of the touchscreen feature tag.
   */
  _validateTouchScreenFeature(
      List<Element> features, Element manifest, ErrorReporter reporter) {
    var feature = features.firstWhere(
        (element) =>
            element.attributes[ANDROID_NAME] == HARDWARE_FEATURE_TOUCHSCREEN,
        orElse: () => null);
    if (feature != null) {
      if (!feature.attributes.containsKey(ANDROID_REQUIRED)) {
        _reportErrorForNode(reporter, feature, ANDROID_NAME,
            ManifestWarningCode.UNSUPPORTED_CHROME_OS_HARDWARE);
      } else if (feature.attributes[ANDROID_REQUIRED] == 'true') {
        _reportErrorForNode(reporter, feature, ANDROID_NAME,
            ManifestWarningCode.UNSUPPORTED_CHROME_OS_FEATURE);
      }
    } else {
      _reportErrorForNode(
          reporter, manifest, null, ManifestWarningCode.NO_TOUCHSCREEN_FEATURE);
    }
  }

  /*
   * Validate the `uses-feature` tags.
   */
  _validateFeatures(List<Element> features, ErrorReporter reporter) {
    var unsupported = features
        .where((element) => UNSUPPORTED_HARDWARE_FEATURES
            .contains(element.attributes[ANDROID_NAME]))
        .toList();
    unsupported.forEach((element) {
      if (!element.attributes.containsKey(ANDROID_REQUIRED)) {
        _reportErrorForNode(reporter, element, ANDROID_NAME,
            ManifestWarningCode.UNSUPPORTED_CHROME_OS_HARDWARE);
      } else if (element.attributes[ANDROID_REQUIRED] == 'true') {
        _reportErrorForNode(reporter, element, ANDROID_NAME,
            ManifestWarningCode.UNSUPPORTED_CHROME_OS_FEATURE);
      }
    });
  }

  /*
   * Validate the `uses-permission` tags.
   */
  _validatePermissions(List<Element> permissions, List<Element> features,
      ErrorReporter reporter) {
    permissions.forEach((permission) {
      if (permission.attributes[ANDROID_NAME] == ANDROID_PERMISSION_CAMERA) {
        if (!_hasFeatureCamera(features) ||
            !_hasFeatureCameraAutoFocus(features)) {
          _reportErrorForNode(reporter, permission, ANDROID_NAME,
              ManifestWarningCode.CAMERA_PERMISSIONS_INCOMPATIBLE);
        }
      } else {
        var featureName =
            getImpliedUnsupportedHardware(permission.attributes[ANDROID_NAME]);
        if (featureName != null) {
          _reportErrorForNode(
              reporter,
              permission,
              ANDROID_NAME,
              ManifestWarningCode.PERMISSION_IMPLIES_UNSUPPORTED_HARDWARE,
              [featureName]);
        }
      }
    });
  }

  /*
   * Validate the 'activity' tags.
   */
  _validateActivities(List<Element> activites, ErrorReporter reporter) {
    activites.forEach((activity) {
      var attributes = activity.attributes;
      if (attributes.containsKey(ATTRIBUTE_SCREEN_ORIENTATION)) {
        var value = attributes[ATTRIBUTE_SCREEN_ORIENTATION];
        if (UNSUPPORTED_ORIENTATIONS
            .contains(attributes[ATTRIBUTE_SCREEN_ORIENTATION])) {
          _reportErrorForNode(reporter, activity, ATTRIBUTE_SCREEN_ORIENTATION,
              ManifestWarningCode.SETTING_ORIENTATION_ON_ACTIVITY);
        }
      }
      if (attributes.containsKey(ATTRIBUTE_RESIZEABLE_ACTIVITY)) {
        if (attributes[ATTRIBUTE_RESIZEABLE_ACTIVITY] == 'false') {
          _reportErrorForNode(reporter, activity, ATTRIBUTE_RESIZEABLE_ACTIVITY,
              ManifestWarningCode.NON_RESIZABLE_ACTIVITY);
        }
      }
    });
  }

  List<Element> _findActivityElements(Element manifest) {
    var applications = manifest?.getElementsByTagName(APPLICATION_TAG);
    var applicationElement = (applications != null && applications.isNotEmpty)
        ? applications.first
        : null;
    var activities =
        applicationElement?.getElementsByTagName(ACTIVITY_TAG) ?? [];
    return activities;
  }

  bool _hasFeatureCamera(List<Element> features) =>
      features.any((f) => f.localName == HARDWARE_FEATURE_CAMERA);

  bool _hasFeatureCameraAutoFocus(List<Element> features) =>
      features.any((f) => f.localName == HARDWARE_FEATURE_CAMERA_AUTOFOCUS);

  /**
   * Report an error for the given node.
   */
  void _reportErrorForNode(
      ErrorReporter reporter, Node node, dynamic key, ErrorCode errorCode,
      [List<Object> arguments]) {
    FileSpan span =
        key == null ? node.sourceSpan : node.attributeValueSpans[key];
    reporter.reportErrorForOffset(
        errorCode, span.start.offset, span.length, arguments);
  }
}
