"use strict";
const iOSProxyServices = require("./ios-proxy-services");
const path = require("path");
const ref = require("ref");
const util = require("util");
const Future = require("fibers/future");
class IOSDeviceFileSystem {
    constructor(device, devicePointer, $coreFoundation, $errors, $fs, $injector, $logger, $mobileDevice, $options) {
        this.device = device;
        this.devicePointer = devicePointer;
        this.$coreFoundation = $coreFoundation;
        this.$errors = $errors;
        this.$fs = $fs;
        this.$injector = $injector;
        this.$logger = $logger;
        this.$mobileDevice = $mobileDevice;
        this.$options = $options;
    }
    listFiles(devicePath, appIdentifier) {
        return (() => {
            if (!devicePath) {
                devicePath = ".";
            }
            this.$logger.info("Listing %s", devicePath);
            let afcClient = this.resolveAfc();
            let walk = (root, indent) => {
                this.$logger.info(util.format("%s %s", Array(indent).join(" "), root));
                let children = [];
                try {
                    children = afcClient.listDir(root);
                }
                catch (e) {
                    children = [];
                }
                _.each(children, (child) => {
                    walk(root + "/" + child, indent + 1);
                });
            };
            walk(devicePath, 0);
        }).future()();
    }
    getFile(deviceFilePath, outputFilePath) {
        let future = new Future();
        let afcClient = this.resolveAfc();
        let fileToRead = afcClient.open(deviceFilePath, "r");
        let fileToWrite = outputFilePath ? this.$fs.createWriteStream(outputFilePath) : process.stdout;
        if (outputFilePath) {
            fileToWrite.on("close", () => {
                future.return();
            });
        }
        let dataSizeToRead = 8192;
        let size = 0;
        while (true) {
            let data = fileToRead.read(dataSizeToRead);
            if (!data || data.length === 0) {
                break;
            }
            fileToWrite.write(data);
            size += data.length;
        }
        fileToRead.close();
        if (outputFilePath) {
            fileToWrite.end();
        }
        this.$logger.trace("%s bytes read from %s", size.toString(), deviceFilePath);
        return future;
    }
    putFile(localFilePath, deviceFilePath) {
        let afcClient = this.resolveAfc();
        return afcClient.transfer(path.resolve(localFilePath), deviceFilePath);
    }
    deleteFile(deviceFilePath, appIdentifier) {
        let houseArrestClient = this.$injector.resolve(iOSProxyServices.HouseArrestClient, { device: this.device });
        let afcClient = this.getAfcClient(houseArrestClient, deviceFilePath, appIdentifier);
        afcClient.deleteFile(deviceFilePath);
        houseArrestClient.closeSocket();
    }
    transferFiles(deviceAppData, localToDevicePaths) {
        return (() => {
            let houseArrestClient = this.$injector.resolve(iOSProxyServices.HouseArrestClient, { device: this.device });
            let afcClient = this.getAfcClient(houseArrestClient, deviceAppData.deviceProjectRootPath, deviceAppData.appIdentifier);
            _.each(localToDevicePaths, (localToDevicePathData) => {
                let stats = this.$fs.getFsStats(localToDevicePathData.getLocalPath());
                if (stats.isFile()) {
                    afcClient.transfer(localToDevicePathData.getLocalPath(), localToDevicePathData.getDevicePath()).wait();
                }
            });
            houseArrestClient.closeSocket();
        }).future()();
    }
    transferDirectory(deviceAppData, localToDevicePaths, projectFilesPath) {
        return this.transferFiles(deviceAppData, localToDevicePaths);
    }
    getAfcClient(houseArrestClient, rootPath, appIdentifier) {
        if (rootPath.indexOf("/Documents/") === 0) {
            return houseArrestClient.getAfcClientForAppDocuments(appIdentifier);
        }
        return houseArrestClient.getAfcClientForAppContainer(appIdentifier);
    }
    resolveAfc() {
        let service = this.$options.app ? this.startHouseArrestService(this.$options.app) : this.device.startService(iOSProxyServices.MobileServices.APPLE_FILE_CONNECTION);
        let afcClient = this.$injector.resolve(iOSProxyServices.AfcClient, { service: service });
        return afcClient;
    }
    startHouseArrestService(bundleId) {
        let func = () => {
            let fdRef = ref.alloc("int");
            let result = this.$mobileDevice.deviceStartHouseArrestService(this.devicePointer, this.$coreFoundation.createCFString(bundleId), null, fdRef);
            let fd = fdRef.deref();
            if (result !== 0) {
                this.$errors.fail("AMDeviceStartHouseArrestService returned %s", result);
            }
            return fd;
        };
        return this.device.tryExecuteFunction(func);
    }
}
exports.IOSDeviceFileSystem = IOSDeviceFileSystem;
