"use strict";
const path = require("path");
const constants_1 = require("../constants");
const prepareInfoFileName = ".nsprepareinfo";
class ProjectChangesInfo {
    get hasChanges() {
        return this.packageChanged ||
            this.appFilesChanged ||
            this.appResourcesChanged ||
            this.modulesChanged ||
            this.configChanged;
    }
    get changesRequireBuild() {
        return this.packageChanged ||
            this.appResourcesChanged ||
            this.nativeChanged;
    }
}
class ProjectChangesService {
    constructor($platformsData, $devicePlatformsConstants, $options, $fs) {
        this.$platformsData = $platformsData;
        this.$devicePlatformsConstants = $devicePlatformsConstants;
        this.$options = $options;
        this.$fs = $fs;
        this._newFiles = 0;
    }
    get currentChanges() {
        return this._changesInfo;
    }
    checkForChanges(platform, projectData) {
        let platformData = this.$platformsData.getPlatformData(platform, projectData);
        this._changesInfo = new ProjectChangesInfo();
        if (!this.ensurePrepareInfo(platform, projectData)) {
            this._newFiles = 0;
            this._changesInfo.appFilesChanged = this.containsNewerFiles(projectData.appDirectoryPath, projectData.appResourcesDirectoryPath, projectData);
            this._changesInfo.packageChanged = this.filesChanged([path.join(projectData.projectDir, "package.json")]);
            this._changesInfo.appResourcesChanged = this.containsNewerFiles(projectData.appResourcesDirectoryPath, null, projectData);
            this._changesInfo.nativeChanged = this.containsNewerFiles(path.join(projectData.projectDir, constants_1.NODE_MODULES_FOLDER_NAME), path.join(projectData.projectDir, constants_1.NODE_MODULES_FOLDER_NAME, "tns-ios-inspector"), projectData, this.fileChangeRequiresBuild);
            if (this._newFiles > 0) {
                this._changesInfo.modulesChanged = true;
            }
            let platformResourcesDir = path.join(projectData.appResourcesDirectoryPath, platformData.normalizedPlatformName);
            if (platform === this.$devicePlatformsConstants.iOS.toLowerCase()) {
                this._changesInfo.configChanged = this.filesChanged([path.join(platformResourcesDir, platformData.configurationFileName),
                    path.join(platformResourcesDir, "LaunchScreen.storyboard"),
                    path.join(platformResourcesDir, "build.xcconfig")
                ]);
            }
            else {
                this._changesInfo.configChanged = this.filesChanged([
                    path.join(platformResourcesDir, platformData.configurationFileName),
                    path.join(platformResourcesDir, "app.gradle")
                ]);
            }
        }
        if (platform.toLowerCase() === this.$devicePlatformsConstants.iOS.toLowerCase()) {
            const nextCommandProvisionUUID = this.$options.provision;
            const prevProvisionUUID = this._prepareInfo.iOSProvisioningProfileUUID;
            if (nextCommandProvisionUUID !== prevProvisionUUID) {
                this._changesInfo.nativeChanged = true;
                this._changesInfo.configChanged = true;
                this._prepareInfo.iOSProvisioningProfileUUID = nextCommandProvisionUUID;
            }
        }
        if (this.$options.bundle !== this._prepareInfo.bundle || this.$options.release !== this._prepareInfo.release) {
            this._changesInfo.appFilesChanged = true;
            this._changesInfo.appResourcesChanged = true;
            this._changesInfo.modulesChanged = true;
            this._changesInfo.configChanged = true;
            this._prepareInfo.release = this.$options.release;
            this._prepareInfo.bundle = this.$options.bundle;
        }
        if (this._changesInfo.packageChanged) {
            this._changesInfo.modulesChanged = true;
        }
        if (this._changesInfo.modulesChanged || this._changesInfo.appResourcesChanged) {
            this._changesInfo.configChanged = true;
        }
        if (this._changesInfo.hasChanges) {
            this._prepareInfo.changesRequireBuild = this._changesInfo.changesRequireBuild;
            this._prepareInfo.time = new Date().toString();
            if (this._prepareInfo.changesRequireBuild) {
                this._prepareInfo.changesRequireBuildTime = this._prepareInfo.time;
            }
        }
        return this._changesInfo;
    }
    getPrepareInfoFilePath(platform, projectData) {
        let platformData = this.$platformsData.getPlatformData(platform, projectData);
        let prepareInfoFilePath = path.join(platformData.projectRoot, prepareInfoFileName);
        return prepareInfoFilePath;
    }
    getPrepareInfo(platform, projectData) {
        let prepareInfoFilePath = this.getPrepareInfoFilePath(platform, projectData);
        let prepareInfo = null;
        if (this.$fs.exists(prepareInfoFilePath)) {
            try {
                prepareInfo = this.$fs.readJson(prepareInfoFilePath);
            }
            catch (e) {
                prepareInfo = null;
            }
        }
        return prepareInfo;
    }
    savePrepareInfo(platform, projectData) {
        let prepareInfoFilePath = this.getPrepareInfoFilePath(platform, projectData);
        this.$fs.writeJson(prepareInfoFilePath, this._prepareInfo);
    }
    ensurePrepareInfo(platform, projectData) {
        this._prepareInfo = this.getPrepareInfo(platform, projectData);
        if (this._prepareInfo) {
            let platformData = this.$platformsData.getPlatformData(platform, projectData);
            let prepareInfoFile = path.join(platformData.projectRoot, prepareInfoFileName);
            this._outputProjectMtime = this.$fs.getFsStats(prepareInfoFile).mtime.getTime();
            this._outputProjectCTime = this.$fs.getFsStats(prepareInfoFile).ctime.getTime();
            return false;
        }
        this._prepareInfo = {
            time: "",
            bundle: this.$options.bundle,
            release: this.$options.release,
            changesRequireBuild: true,
            changesRequireBuildTime: null
        };
        this._outputProjectMtime = 0;
        this._outputProjectCTime = 0;
        this._changesInfo.appFilesChanged = true;
        this._changesInfo.appResourcesChanged = true;
        this._changesInfo.modulesChanged = true;
        this._changesInfo.configChanged = true;
        return true;
    }
    filesChanged(files) {
        for (let file of files) {
            if (this.$fs.exists(file)) {
                let fileStats = this.$fs.getFsStats(file);
                if (fileStats.mtime.getTime() >= this._outputProjectMtime || fileStats.ctime.getTime() >= this._outputProjectCTime) {
                    return true;
                }
            }
        }
        return false;
    }
    containsNewerFiles(dir, skipDir, projectData, processFunc) {
        let files = this.$fs.readDirectory(dir);
        for (let file of files) {
            let filePath = path.join(dir, file);
            if (filePath === skipDir) {
                continue;
            }
            let fileStats = this.$fs.getFsStats(filePath);
            let changed = fileStats.mtime.getTime() >= this._outputProjectMtime || fileStats.ctime.getTime() >= this._outputProjectCTime;
            if (!changed) {
                let lFileStats = this.$fs.getLsStats(filePath);
                changed = lFileStats.mtime.getTime() >= this._outputProjectMtime || lFileStats.ctime.getTime() >= this._outputProjectCTime;
            }
            if (changed) {
                if (processFunc) {
                    this._newFiles++;
                    let filePathRelative = path.relative(projectData.projectDir, filePath);
                    if (processFunc.call(this, filePathRelative, projectData)) {
                        return true;
                    }
                }
                else {
                    return true;
                }
            }
            if (fileStats.isDirectory()) {
                if (this.containsNewerFiles(filePath, skipDir, projectData, processFunc)) {
                    return true;
                }
            }
        }
        return false;
    }
    fileChangeRequiresBuild(file, projectData) {
        if (path.basename(file) === "package.json") {
            return true;
        }
        let projectDir = projectData.projectDir;
        if (_.startsWith(path.join(projectDir, file), projectData.appResourcesDirectoryPath)) {
            return true;
        }
        if (_.startsWith(file, constants_1.NODE_MODULES_FOLDER_NAME)) {
            let filePath = file;
            while (filePath !== constants_1.NODE_MODULES_FOLDER_NAME) {
                filePath = path.dirname(filePath);
                let fullFilePath = path.join(projectDir, path.join(filePath, "package.json"));
                if (this.$fs.exists(fullFilePath)) {
                    let json = this.$fs.readJson(fullFilePath);
                    if (json["nativescript"] && _.startsWith(file, path.join(filePath, "platforms"))) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
}
exports.ProjectChangesService = ProjectChangesService;
$injector.register("projectChangesService", ProjectChangesService);
