/**
 * @license Angular v21.2.1
 * (c) 2010-2026 Google LLC. https://angular.dev/
 * License: MIT
 */

import * as i0 from '@angular/core';
import { inject, Injectable, InjectionToken, DOCUMENT, Optional, Inject, ɵɵinject as __inject } from '@angular/core';
import { Subject } from 'rxjs';
import { PlatformLocation } from './_platform_location-chunk.mjs';

function joinWithSlash(start, end) {
  if (!start) return end;
  if (!end) return start;
  if (start.endsWith('/')) {
    return end.startsWith('/') ? start + end.slice(1) : start + end;
  }
  return end.startsWith('/') ? start + end : `${start}/${end}`;
}
function stripTrailingSlash(url) {
  const pathEndIdx = url.search(/#|\?|$/);
  return url[pathEndIdx - 1] === '/' ? url.slice(0, pathEndIdx - 1) + url.slice(pathEndIdx) : url;
}
function normalizeQueryParams(params) {
  return params && params[0] !== '?' ? `?${params}` : params;
}

class LocationStrategy {
  historyGo(relativePosition) {
    throw new Error(ngDevMode ? 'Not implemented' : '');
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: LocationStrategy,
    deps: [],
    target: i0.ɵɵFactoryTarget.Injectable
  });
  static ɵprov = i0.ɵɵngDeclareInjectable({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: LocationStrategy,
    providedIn: 'root',
    useFactory: () => inject(PathLocationStrategy)
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "21.2.1",
  ngImport: i0,
  type: LocationStrategy,
  decorators: [{
    type: Injectable,
    args: [{
      providedIn: 'root',
      useFactory: () => inject(PathLocationStrategy)
    }]
  }]
});
const APP_BASE_HREF = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'appBaseHref' : '');
class PathLocationStrategy extends LocationStrategy {
  _platformLocation;
  _baseHref;
  _removeListenerFns = [];
  constructor(_platformLocation, href) {
    super();
    this._platformLocation = _platformLocation;
    this._baseHref = href ?? this._platformLocation.getBaseHrefFromDOM() ?? inject(DOCUMENT).location?.origin ?? '';
  }
  ngOnDestroy() {
    while (this._removeListenerFns.length) {
      this._removeListenerFns.pop()();
    }
  }
  onPopState(fn) {
    this._removeListenerFns.push(this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn));
  }
  getBaseHref() {
    return this._baseHref;
  }
  prepareExternalUrl(internal) {
    return joinWithSlash(this._baseHref, internal);
  }
  path(includeHash = false) {
    const pathname = this._platformLocation.pathname + normalizeQueryParams(this._platformLocation.search);
    const hash = this._platformLocation.hash;
    return hash && includeHash ? `${pathname}${hash}` : pathname;
  }
  pushState(state, title, url, queryParams) {
    const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));
    this._platformLocation.pushState(state, title, externalUrl);
  }
  replaceState(state, title, url, queryParams) {
    const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));
    this._platformLocation.replaceState(state, title, externalUrl);
  }
  forward() {
    this._platformLocation.forward();
  }
  back() {
    this._platformLocation.back();
  }
  getState() {
    return this._platformLocation.getState();
  }
  historyGo(relativePosition = 0) {
    this._platformLocation.historyGo?.(relativePosition);
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: PathLocationStrategy,
    deps: [{
      token: PlatformLocation
    }, {
      token: APP_BASE_HREF,
      optional: true
    }],
    target: i0.ɵɵFactoryTarget.Injectable
  });
  static ɵprov = i0.ɵɵngDeclareInjectable({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: PathLocationStrategy,
    providedIn: 'root'
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "21.2.1",
  ngImport: i0,
  type: PathLocationStrategy,
  decorators: [{
    type: Injectable,
    args: [{
      providedIn: 'root'
    }]
  }],
  ctorParameters: () => [{
    type: PlatformLocation
  }, {
    type: undefined,
    decorators: [{
      type: Optional
    }, {
      type: Inject,
      args: [APP_BASE_HREF]
    }]
  }]
});
class NoTrailingSlashPathLocationStrategy extends PathLocationStrategy {
  prepareExternalUrl(internal) {
    const path = extractUrlPath(internal);
    if (path.endsWith('/') && path.length > 1) {
      internal = path.slice(0, -1) + internal.slice(path.length);
    }
    return super.prepareExternalUrl(internal);
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: NoTrailingSlashPathLocationStrategy,
    deps: null,
    target: i0.ɵɵFactoryTarget.Injectable
  });
  static ɵprov = i0.ɵɵngDeclareInjectable({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: NoTrailingSlashPathLocationStrategy,
    providedIn: 'root'
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "21.2.1",
  ngImport: i0,
  type: NoTrailingSlashPathLocationStrategy,
  decorators: [{
    type: Injectable,
    args: [{
      providedIn: 'root'
    }]
  }]
});
class TrailingSlashPathLocationStrategy extends PathLocationStrategy {
  prepareExternalUrl(internal) {
    const path = extractUrlPath(internal);
    if (!path.endsWith('/')) {
      internal = path + '/' + internal.slice(path.length);
    }
    return super.prepareExternalUrl(internal);
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: TrailingSlashPathLocationStrategy,
    deps: null,
    target: i0.ɵɵFactoryTarget.Injectable
  });
  static ɵprov = i0.ɵɵngDeclareInjectable({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: TrailingSlashPathLocationStrategy,
    providedIn: 'root'
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "21.2.1",
  ngImport: i0,
  type: TrailingSlashPathLocationStrategy,
  decorators: [{
    type: Injectable,
    args: [{
      providedIn: 'root'
    }]
  }]
});
function extractUrlPath(url) {
  const questionMarkOrHashIndex = url.search(/[?#]/);
  const pathEnd = questionMarkOrHashIndex > -1 ? questionMarkOrHashIndex : url.length;
  return url.slice(0, pathEnd);
}

class Location {
  _subject = new Subject();
  _basePath;
  _locationStrategy;
  _urlChangeListeners = [];
  _urlChangeSubscription = null;
  constructor(locationStrategy) {
    this._locationStrategy = locationStrategy;
    const baseHref = this._locationStrategy.getBaseHref();
    this._basePath = _stripOrigin(stripTrailingSlash(_stripIndexHtml(baseHref)));
    this._locationStrategy.onPopState(ev => {
      this._subject.next({
        'url': this.path(true),
        'pop': true,
        'state': ev.state,
        'type': ev.type
      });
    });
  }
  ngOnDestroy() {
    this._urlChangeSubscription?.unsubscribe();
    this._urlChangeListeners = [];
  }
  path(includeHash = false) {
    return this.normalize(this._locationStrategy.path(includeHash));
  }
  getState() {
    return this._locationStrategy.getState();
  }
  isCurrentPathEqualTo(path, query = '') {
    return this.path() == this.normalize(path + normalizeQueryParams(query));
  }
  normalize(url) {
    return Location.stripTrailingSlash(_stripBasePath(this._basePath, _stripIndexHtml(url)));
  }
  prepareExternalUrl(url) {
    if (url && url[0] !== '/') {
      url = '/' + url;
    }
    return this._locationStrategy.prepareExternalUrl(url);
  }
  go(path, query = '', state = null) {
    this._locationStrategy.pushState(state, '', path, query);
    this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state);
  }
  replaceState(path, query = '', state = null) {
    this._locationStrategy.replaceState(state, '', path, query);
    this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state);
  }
  forward() {
    this._locationStrategy.forward();
  }
  back() {
    this._locationStrategy.back();
  }
  historyGo(relativePosition = 0) {
    this._locationStrategy.historyGo?.(relativePosition);
  }
  onUrlChange(fn) {
    this._urlChangeListeners.push(fn);
    this._urlChangeSubscription ??= this.subscribe(v => {
      this._notifyUrlChangeListeners(v.url, v.state);
    });
    return () => {
      const fnIndex = this._urlChangeListeners.indexOf(fn);
      this._urlChangeListeners.splice(fnIndex, 1);
      if (this._urlChangeListeners.length === 0) {
        this._urlChangeSubscription?.unsubscribe();
        this._urlChangeSubscription = null;
      }
    };
  }
  _notifyUrlChangeListeners(url = '', state) {
    this._urlChangeListeners.forEach(fn => fn(url, state));
  }
  subscribe(onNext, onThrow, onReturn) {
    return this._subject.subscribe({
      next: onNext,
      error: onThrow ?? undefined,
      complete: onReturn ?? undefined
    });
  }
  static normalizeQueryParams = normalizeQueryParams;
  static joinWithSlash = joinWithSlash;
  static stripTrailingSlash = stripTrailingSlash;
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: Location,
    deps: [{
      token: LocationStrategy
    }],
    target: i0.ɵɵFactoryTarget.Injectable
  });
  static ɵprov = i0.ɵɵngDeclareInjectable({
    minVersion: "12.0.0",
    version: "21.2.1",
    ngImport: i0,
    type: Location,
    providedIn: 'root',
    useFactory: createLocation
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "21.2.1",
  ngImport: i0,
  type: Location,
  decorators: [{
    type: Injectable,
    args: [{
      providedIn: 'root',
      useFactory: createLocation
    }]
  }],
  ctorParameters: () => [{
    type: LocationStrategy
  }]
});
function createLocation() {
  return new Location(__inject(LocationStrategy));
}
function _stripBasePath(basePath, url) {
  if (!basePath || !url.startsWith(basePath)) {
    return url;
  }
  const strippedUrl = url.substring(basePath.length);
  if (strippedUrl === '' || ['/', ';', '?', '#'].includes(strippedUrl[0])) {
    return strippedUrl;
  }
  return url;
}
function _stripIndexHtml(url) {
  return url.replace(/\/index.html$/, '');
}
function _stripOrigin(baseHref) {
  const isAbsoluteUrl = new RegExp('^(https?:)?//').test(baseHref);
  if (isAbsoluteUrl) {
    const [, pathname] = baseHref.split(/\/\/[^\/]+/);
    return pathname;
  }
  return baseHref;
}

export { APP_BASE_HREF, Location, LocationStrategy, NoTrailingSlashPathLocationStrategy, PathLocationStrategy, TrailingSlashPathLocationStrategy, joinWithSlash, normalizeQueryParams };
//# sourceMappingURL=_location-chunk.mjs.map
