// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

library webdriver.src.firefox_profile;

import 'dart:io' as io;
import 'package:path/path.dart' as path;
import 'dart:collection';
import 'dart:convert' show LineSplitter;
import 'package:archive/archive.dart' show Archive, ArchiveFile, ZipEncoder;
import 'package:crypto/crypto.dart' show CryptoUtils;

/// Unmodifiable defaults for 'prefs.js' and 'user.js'.
final lockedPrefs = [
  new BooleanOption("app.update.auto", false),
  new BooleanOption("app.update.enabled", false),
  new IntegerOption("browser.displayedE10SNotice", 4),
  new BooleanOption("browser.download.manager.showWhenStarting", false),
  new BooleanOption("browser.EULA.override", true),
  new BooleanOption("browser.EULA.3.accepted", true),
  new IntegerOption("browser.link.open_external", 2),
  new IntegerOption("browser.link.open_newwindow", 2),
  new BooleanOption("browser.offline", false),
  new BooleanOption("browser.reader.detectedFirstArticle", true),
  new BooleanOption("browser.safebrowsing.enabled", false),
  new BooleanOption("browser.safebrowsing.malware.enabled", false),
  new BooleanOption("browser.search.update", false),
  new StringOption("browser.selfsupport.url", ""),
  new BooleanOption("browser.sessionstore.resume_from_crash", false),
  new BooleanOption("browser.shell.checkDefaultBrowser", false),
  new BooleanOption("browser.tabs.warnOnClose", false),
  new BooleanOption("browser.tabs.warnOnOpen", false),
  new BooleanOption("datareporting.healthreport.service.enabled", false),
  new BooleanOption("datareporting.healthreport.uploadEnabled", false),
  new BooleanOption("datareporting.healthreport.service.firstRun", false),
  new BooleanOption("datareporting.healthreport.logging.consoleEnabled", false),
  new BooleanOption("datareporting.policy.dataSubmissionEnabled", false),
  new BooleanOption("datareporting.policy.dataSubmissionPolicyAccepted", false),
  new BooleanOption("devtools.errorconsole.enabled", true),
  new BooleanOption("dom.disable_open_during_load", false),
  new IntegerOption("extensions.autoDisableScopes", 10),
  new BooleanOption("extensions.blocklist.enabled", false),
  new BooleanOption("extensions.logging.enabled", true),
  new BooleanOption("extensions.update.enabled", false),
  new BooleanOption("extensions.update.notifyUser", false),
  new BooleanOption("javascript.enabled", true),
  new BooleanOption("network.manage-offline-status", false),
  new IntegerOption("network.http.phishy-userpass-length", 255),
  new BooleanOption("offline-apps.allow_by_default", true),
  new BooleanOption("prompts.tab_modal.enabled", false),
  new BooleanOption("security.csp.enable", false),
  new IntegerOption("security.fileuri.origin_policy", 3),
  new BooleanOption("security.fileuri.strict_origin_policy", false),
  new BooleanOption("security.warn_entering_secure", false),
  new BooleanOption("security.warn_entering_secure.show_once", false),
  new BooleanOption("security.warn_entering_weak", false),
  new BooleanOption("security.warn_entering_weak.show_once", false),
  new BooleanOption("security.warn_leaving_secure", false),
  new BooleanOption("security.warn_leaving_secure.show_once", false),
  new BooleanOption("security.warn_submit_insecure", false),
  new BooleanOption("security.warn_viewing_mixed", false),
  new BooleanOption("security.warn_viewing_mixed.show_once", false),
  new BooleanOption("signon.rememberSignons", false),
  new BooleanOption("toolkit.networkmanager.disable", true),
  new IntegerOption("toolkit.telemetry.prompted", 2),
  new BooleanOption("toolkit.telemetry.enabled", false),
  new BooleanOption("toolkit.telemetry.rejected", true),
  new BooleanOption("xpinstall.signatures.required", false),
];

/// Default values for 'user.js'.
final defaultUserPrefs = [
  new BooleanOption("browser.dom.window.dump.enabled", true),
  new StringOption("browser.newtab.url", "about:blank"),
  new BooleanOption("browser.newtabpage.enabled", false),
  new IntegerOption("browser.startup.page", 0),
  new StringOption("browser.startup.homepage", "about:blank"),
  new IntegerOption("dom.max_chrome_script_run_time", 30),
  new IntegerOption("dom.max_script_run_time", 30),
  new BooleanOption("dom.report_all_js_exceptions", true),
  new BooleanOption("javascript.options.showInConsole", true),
  new IntegerOption("network.http.max-connections-per-server", 10),
  new StringOption("startup.homepage_welcome_url", "about:blank"),
  new BooleanOption("webdriver_accept_untrusted_certs", true),
  new BooleanOption("webdriver_assume_untrusted_issuer", true),
];

/// Creates a Firefox profile in a format so it can be passed using the
/// `desired` capabilities map.
class FirefoxProfile {
  final io.Directory profileDirectory;

  Set<PrefsOption> _prefs = new Set<PrefsOption>();

  /// The read-only settings of the `prefs.js` file of the profile directory.
  List<PrefsOption> get prefs => new UnmodifiableListView<PrefsOption>(_prefs);

  /// The settings of the `user.js` file of the profile directory overridden by
  /// the settings in [lockedPrefs].
  /// [setOption] and [removeOption] allow to update, add, and remove settings
  /// except these included in [lockedPrefs].
  Set<PrefsOption> _userPrefs = new Set<PrefsOption>();
  List<PrefsOption> get userPrefs =>
      new UnmodifiableListView<PrefsOption>(_userPrefs);

  FirefoxProfile({this.profileDirectory}) {
    _userPrefs.addAll(defaultUserPrefs);
    if (profileDirectory != null) {
      final prefsFile =
          new io.File(path.join(profileDirectory.absolute.path, 'prefs.js'));
      if (prefsFile.existsSync()) {
        _prefs = loadPrefsFile(prefsFile);
      }

      final userPrefsFile =
          new io.File(path.join(profileDirectory.absolute.path, 'user.js'));
      if (userPrefsFile.existsSync()) {
        _userPrefs = loadPrefsFile(userPrefsFile);
      }
    }
    _prefs.addAll(lockedPrefs);
  }

  /// Add an option or replace an option if one already exists with the same
  /// name.
  /// If option exists in [lockedPrefs] it will not be added.
  /// Returns `true` if [userPrefs] was updated, `false` otherwise.
  bool setOption(PrefsOption option) {
    if (lockedPrefs.contains(option)) {
      print('Option "${option.name}" (${option.value}) is locked and therefore '
          'ignored');
      return false;
    }
    _userPrefs.add(option);
    return true;
  }

  /// Remove the option named [name] from [userPrefs].
  /// If [lockedPrefs] contains this option it will not be removed.
  /// Returns `true` if [userPrefs] was removed, `false` if it was not removed
  /// because [userPrefs] doesn't contain it because [lockedPrefs]
  /// contains it.
  bool removeOption(String name) {
    final option = _userPrefs.firstWhere((o) => o.name == name,
        orElse: () => new InvalidOption(name));
    if (option is InvalidOption) {
      return false;
    }
    return _userPrefs.remove(option);
  }

  /// Helper for [loadPrefsFile]
  static bool _ignoreLine(String line) {
    line ??= '';
    line = line.trim();
    if (line.isEmpty ||
        line.startsWith('//') ||
        line.startsWith('#') ||
        line.startsWith('/*') ||
        line.startsWith('*') ||
        line.startsWith('*/')) {
      return true;
    }
    return false;
  }

  /// Load a prefs file and parse the content into a set of [PrefOption].
  /// For lines which can't be properly parsed a message is printed and the line
  /// is otherwise ignored.
  /// Comments, lines starting with `//` are silently ignored.
  static Set<PrefsOption> loadPrefsFile(io.File file) {
    final prefs = new Set<PrefsOption>();
    final lines = LineSplitter
        .split(file.readAsStringSync())
        .where((line) => !_ignoreLine(line));
    bool canNotParseCaption = true;

    for (final line in lines) {
      final option = new PrefsOption.parse(line);
      if (option is InvalidOption) {
        if (canNotParseCaption) {
          print('Can\'t parse lines from file "${file.path}":');
          canNotParseCaption = false;
        }
        print('  ${line}');
        continue;
      }
      prefs.add(option);
    }
    return prefs;
  }

  /// Creates a map like `{'browserName: 'firefox', 'firefox_profile': 'xxxxx'}`
  /// where `xxxxx` is the zipped and base64 encoded content of the files in
  /// [profileDirectory] if one was pased.
  /// The files `prefs.js` and `user.js` are generated from the content of
  /// `prefs` and `userPrefs`.
  /// It can be uses like
  /// `var desired = Capabilities.firefox..addAll(firefoxProfile.toJson()}`
  Map toJson() {
    Archive archive = new Archive();
    if (profileDirectory != null) {
      profileDirectory.listSync(recursive: true).forEach((f) {
        ArchiveFile archiveFile;
        final name = path.relative(f.path, from: profileDirectory.path);
        if (f is io.Directory) {
          archiveFile = new ArchiveFile('${name}/', 0, []);
        } else if (f is io.File) {
          if (name == 'prefs.js' || name == 'user.js') {
            return;
          }
          archiveFile = new ArchiveFile(
              name, f.statSync().size, (f as io.File).readAsBytesSync());
        } else {
          throw 'Invalid file type for file "${f.path}" (${io.FileSystemEntity.typeSync(f.path)}).';
        }
        archive.addFile(archiveFile);
      });
    }
    final prefsJsContent =
        prefs.map((option) => option.asPrefString).join('\n').codeUnits;
    archive.addFile(
        new ArchiveFile('prefs.js', prefsJsContent.length, prefsJsContent));

    final userJsContent =
        userPrefs.map((option) => option.asPrefString).join('\n').codeUnits;
    archive.addFile(
        new ArchiveFile('user.js', userJsContent.length, userJsContent));

    final zipData = new ZipEncoder().encode(archive);
    return {'firefox_profile': CryptoUtils.bytesToBase64(zipData)};
  }
}

abstract class PrefsOption<T> {
  /// This pattern is used to parse preferences in user.js. It is intended to
  /// match all preference lines in the format generated by Firefox; it won't
  /// necessarily match all possible lines that Firefox will parse.
  ///
  /// e.g. if you have a line with extra spaces after the end-of-line semicolon,
  /// this pattern will not match that line because Firefox never generates
  /// lines like that.
  static final RegExp _preferencePattern =
      new RegExp(r'user_pref\("([^"]+)", ("?.+?"?)\);');

  final String name;
  T _value;
  dynamic get value => _value;

  factory PrefsOption(String name, value) {
    assert(value is bool || value is int || value is String);
    if (value is bool) {
      return new BooleanOption(name, value) as PrefsOption<T>;
    } else if (value is int) {
      return new IntegerOption(name, value) as PrefsOption<T>;
    } else if (value is String) {
      return new StringOption(name, value) as PrefsOption<T>;
    }
  }

  factory PrefsOption.parse(String prefs) {
    final match = _preferencePattern.firstMatch(prefs);
    if (match == null) {
      return new InvalidOption('Not a valid prefs option: "${prefs}".')
          as PrefsOption<T>;
    }
    final name = match.group(1);
    final valueString = match.group(2);
    if (valueString.startsWith('"') && valueString.endsWith('"')) {
      final value = valueString
          .substring(1, valueString.length - 1)
          .replaceAll(r'\"', r'"')
          .replaceAll(r'\\', r'\');
      return new StringOption(name, value) as PrefsOption<T>;
    }
    if (valueString.toLowerCase() == 'true') {
      return new BooleanOption(name, true) as PrefsOption<T>;
    } else if (valueString.toLowerCase() == 'false') {
      return new BooleanOption(name, false) as PrefsOption<T>;
    }
    try {
      int value = int.parse(valueString);
      return new IntegerOption(name, value) as PrefsOption<T>;
    } catch (_) {}
    return new InvalidOption('Not a valid prefs option: "${prefs}".')
        as PrefsOption<T>;
  }

  PrefsOption._(this.name, [this._value]) {
    assert(name.isNotEmpty);
  }

  bool operator ==(other) {
    if (other is! PrefsOption) return false;
    return other.name == name;
  }

  @override
  int get hashCode => name.hashCode;

  String get asPrefString => 'user_pref("${name}", ${_valueAsPrefString});';

  String get _valueAsPrefString;
}

/// Used as a placeholder for unparsable lines.
class InvalidOption extends PrefsOption<String> {
  InvalidOption(String value) : super._('invalid', value);

  @override
  String get _valueAsPrefString =>
      throw 'An invalid option can\'t be serialized.';
}

/// A boolean preferences option with name and value.
class BooleanOption extends PrefsOption<bool> {
  BooleanOption(String name, bool value) : super._(name, value);

  @override
  String get _valueAsPrefString => value.toString();
}

/// An integer preferences option with name and value.
class IntegerOption extends PrefsOption<int> {
  IntegerOption(String name, int value) : super._(name, value);

  @override
  String get _valueAsPrefString => value.toString();
}

/// A String preferences option with name and value.
/// [_valueAsPrefString] escapes `"` as `\"` and `\` as `\\`.
class StringOption extends PrefsOption<String> {
  StringOption(String name, String value) : super._(name, value);

  String _escape(String value) =>
      value.replaceAll(r'\', r'\\').replaceAll('"', r'\"');
  @override
  String get _valueAsPrefString {
    return '"${_escape(value)}"';
  }
}
