import * as url from '../util/url';
const parsePosition = (str) => {
    const split = str.split(',');
    if (split.length === 1) {
        return { line: parseInt(str, 10), character: 0 };
    }
    if (split.length === 2) {
        return { line: parseInt(split[0], 10), character: parseInt(split[1], 10) };
    }
    throw new Error('unexpected position: ' + str);
};
/**
 * Parses the properties of a repo URI like git://github.com/gorilla/mux#mux.go
 */
export function parseRepoURI(uri) {
    const parsed = new URL(uri);
    const repoPath = parsed.hostname + parsed.pathname;
    const rev = parsed.search.substr('?'.length) || undefined;
    let commitID;
    if (rev && rev.match(/[0-9a-fA-f]{40}/)) {
        commitID = rev;
    }
    const fragmentSplit = parsed.hash.substr('#'.length).split(':');
    let filePath;
    let position;
    let range;
    if (fragmentSplit.length === 1) {
        filePath = fragmentSplit[0];
    }
    if (fragmentSplit.length === 2) {
        filePath = fragmentSplit[0];
        const rangeOrPosition = fragmentSplit[1];
        const rangeOrPositionSplit = rangeOrPosition.split('-');
        if (rangeOrPositionSplit.length === 1) {
            position = parsePosition(rangeOrPositionSplit[0]);
        }
        if (rangeOrPositionSplit.length === 2) {
            range = { start: parsePosition(rangeOrPositionSplit[0]), end: parsePosition(rangeOrPositionSplit[1]) };
        }
        if (rangeOrPositionSplit.length > 2) {
            throw new Error('unexpected range or position: ' + rangeOrPosition);
        }
    }
    if (fragmentSplit.length > 2) {
        throw new Error('unexpected fragment: ' + parsed.hash);
    }
    return { repoPath, rev, commitID, filePath: filePath || undefined, position, range };
}
/**
 * Parses a repo-rev string like "my/repo@my/rev" to the repo and rev components.
 */
export function parseRepoRev(repoRev) {
    const [repo, rev] = repoRev.split('@', 2);
    return {
        repoPath: decodeURIComponent(repo),
        rev: rev && decodeURIComponent(rev),
        rawRev: rev,
    };
}
/**
 * Parses the properties of a blob URL.
 */
export function parseBrowserRepoURL(href) {
    const loc = new URL(href, window.location.href);
    let pathname = loc.pathname.slice(1); // trim leading '/'
    if (pathname.endsWith('/')) {
        pathname = pathname.substr(0, pathname.length - 1); // trim trailing '/'
    }
    const indexOfSep = pathname.indexOf('/-/');
    // examples:
    // - 'github.com/gorilla/mux'
    // - 'github.com/gorilla/mux@revision'
    // - 'foo/bar' (from 'sourcegraph.mycompany.com/foo/bar')
    // - 'foo/bar@revision' (from 'sourcegraph.mycompany.com/foo/bar@revision')
    // - 'foobar' (from 'sourcegraph.mycompany.com/foobar')
    // - 'foobar@revision' (from 'sourcegraph.mycompany.com/foobar@revision')
    let repoRev;
    if (indexOfSep === -1) {
        repoRev = pathname; // the whole string
    }
    else {
        repoRev = pathname.substring(0, indexOfSep); // the whole string leading up to the separator (allows rev to be multiple path parts)
    }
    const { repoPath, rev } = parseRepoRev(repoRev);
    if (!repoPath) {
        throw new Error('unexpected repo url: ' + href);
    }
    const commitID = rev && /^[a-f0-9]{40}$/i.test(rev) ? rev : undefined;
    let filePath;
    const treeSep = pathname.indexOf('/-/tree/');
    const blobSep = pathname.indexOf('/-/blob/');
    if (treeSep !== -1) {
        filePath = pathname.substr(treeSep + '/-/tree/'.length);
    }
    if (blobSep !== -1) {
        filePath = pathname.substr(blobSep + '/-/blob/'.length);
    }
    let position;
    let range;
    if (loc.hash) {
        const parsedHash = url.parseHash(loc.hash.substr('#'.length));
        if (parsedHash.line) {
            position = {
                line: parsedHash.line,
                character: parsedHash.character || 0,
            };
            if (parsedHash.endLine) {
                range = {
                    start: position,
                    end: {
                        line: parsedHash.endLine,
                        character: parsedHash.endCharacter || 0,
                    },
                };
            }
        }
    }
    return { repoPath, rev, commitID, filePath, position, range };
}
/**
 * Replaces the revision in the given URL, or adds one if there is not already
 * one.
 * @param href The URL whose revision should be replaced.
 */
export function replaceRevisionInURL(href, newRev) {
    const parsed = parseBrowserRepoURL(window.location.href);
    const repoRev = `/${url.encodeRepoRev(parsed.repoPath, parsed.rev)}`;
    const u = new URL(window.location.href);
    u.pathname = `/${url.encodeRepoRev(parsed.repoPath, newRev)}${u.pathname.slice(repoRev.length)}`;
    return `${u.pathname}${u.search}${u.hash}`;
}
const positionStr = (pos) => pos.line + '' + (pos.character ? ',' + pos.character : '');
/**
 * The inverse of parseRepoURI, this generates a string from parsed values.
 */
export function makeRepoURI(parsed) {
    const rev = parsed.commitID || parsed.rev;
    let uri = `git://${parsed.repoPath}`;
    uri += rev ? '?' + rev : '';
    uri += parsed.filePath ? '#' + parsed.filePath : '';
    uri += parsed.position || parsed.range ? ':' : '';
    uri += parsed.position ? positionStr(parsed.position) : '';
    uri += parsed.range ? positionStr(parsed.range.start) + '-' + positionStr(parsed.range.end) : '';
    return uri;
}
/**
 * Retrieves the <td> element at the specified line on the current document.
 */
export function getBlobTableRow(line) {
    const table = document.querySelector('.blob > table');
    return table.rows[line - 1];
}
/**
 * Retrieves the <td> elements for the specified line range (inclusive) on
 * the current document.
 */
export function getBlobTableRows(line, endLine = line) {
    const table = document.querySelector('.blob > table');
    const rows = [];
    for (let i = line; i <= endLine; i++) {
        const cell = table.rows[i - 1];
        if (cell) {
            rows.push(cell);
        }
    }
    return rows;
}
/**
 * Performs a redirect to the host of the given URL with the path, query etc. properties of the current URL.
 */
export function redirectToExternalHost(externalRedirectURL) {
    const externalHostURL = new URL(externalRedirectURL);
    const redirectURL = new URL(window.location.href);
    // Preserve the path of the current URL and redirect to the repo on the external host.
    redirectURL.host = externalHostURL.host;
    redirectURL.port = externalHostURL.port;
    redirectURL.protocol = externalHostURL.protocol;
    window.location.replace(redirectURL.toString());
}
//# sourceMappingURL=index.js.map