// LensUtils
//  allLensIds
//  getLensName(lensId)
//  getBkLensDTOs
//  count

function LensUtils(categoryDTOs, lensDTOs) {

    this._lensDTOs = lensDTOs;

    this._count = lensDTOs.length;

    const catCount = categoryDTOs.length;

    this._catIdToSortOrderHash = {};

    for (var zIndex = 0; zIndex < catCount; zIndex++) {
        var theCat = categoryDTOs[zIndex];

        var catId = theCat.CategoryId;
        var sortIndex = theCat.SortOrder;

        this._catIdToSortOrderHash[catId] = sortIndex;
    }

    this._allLensIds = lensDTOs.map(x => x.LensId);
    // store the ids of all the lenses

    this._allLensNames = lensDTOs.map(x => x.LensName);
    // store the names of all the lenses, in same order as DTOs

    this._allLensNamesSorted = this._allLensNames.slice(0);
    // clone the array so we don't disturb its sort order

    this._allLensNamesSorted.sort();
    // sort the clone

    this._categoryDTOs = categoryDTOs;

    this.getAllLensIds = function getAllLensIds() {
        log('getAllLensIds: enter');
        log('getAllLensIds: leave');

        return this._allLensIds;
    };

    this.categoryIdToSortIndex = function categoryIdToSortIndex(catId) {
        //log('categoryIdToSortIndex: enter');
        //log('categoryIdToSortIndex: catId=' + catId);

        const sortIndex = this._catIdToSortOrderHash[catId];

        //log('categoryIdToSortIndex: sortIndex=' + sortIndex);
        //log('categoryIdToSortIndex: leave');

        return sortIndex;
    };

    this._categoryDTOs.sort(function (a, b) { return (a.SortOrder > b.SortOrder) ? 1 : -1 });
    // sort categories ascending by sort order

    this.getPrevLensName = function getPrevLensName(lensId) {
        log('getPrevLensName: enter');
        log('getPrevLensName: lensId=' + lensId);

        const sortedNames = this._allLensNamesSorted;
        // get all lens names, in alphabetical order

        const lensName = this.getLensName(lensId);

        const where = sortedNames.indexOf(lensName);

        if (where < 0)
            return '';

        var foundIndex = where - 1;

        if (foundIndex < 0)
            foundIndex = sortedNames.length - 1;

        const prevName = sortedNames[foundIndex];

        log('getPrevLensName: prevName=' + prevName);
        log('getPrevLensName: leave');

        return prevName;
    };

    this.getNextLensName = function getNextLensName(lensId) {
        log('getNextLensName: enter');
        log('getNextLensName: lensId=' + lensId);

        const sortedNames = this._allLensNamesSorted;
        // get all lens names, in alphabetical order

        const lensName = this.getLensName(lensId);

        const where = sortedNames.indexOf(lensName);

        if (where < 0)
            return '';

        var foundIndex = where + 1;

        if (foundIndex >= (sortedNames.length))
            foundIndex = 0;

        const nextName = sortedNames[foundIndex];

        log('getNextLensName: nextName=' + nextName);
        log('getNextLensName: leave');

        return nextName;
    };

    this.getLensesInCategories = function getLensesInCategories(lensDTOs) {
        // given an array of lenses, return an array of five arrays
        // each of the arrays in the result represents lenses from the source array in a single group
        // the groups are returned in sort order

        const logHdr = 'lensUtils.getLensesInCategories: ';
        log(logHdr + 'enter');

        const lensCount = lensDTOs.length;

        var result = [
            [],
            [],
            [],
            [],
            []
        ];

        var zIndex;

        for (zIndex = 0; zIndex < lensCount; zIndex++) {
            const lensDTO = lensDTOs[zIndex];

            const catId = lensDTO.CategoryId;

            const sortIndex = this.categoryIdToSortIndex(catId);

            result[sortIndex].push(lensDTO);
            // append the DTO to the array for the category
        }

        for (zIndex = 0; zIndex < 5; zIndex++) {
            // once for each category

            result[zIndex].sort(function (a, b) { return (a.LensName > b.LensName) ? 1 : -1 });
            // sort the lenses in the category by lens name
        }

        log(logHdr + 'leave');

        return result;
    };

    this.count = function count() { return this._count; }

    this.getLensName = function getLensName(lensId) {
        log('getLensName: enter');

        var name = '';

        const where = this._allLensIds.indexOf(lensId);

        if (where >= 0) {
            const dto = this._lensDTOs[where];

            name = dto.LensName;
        }

        log('getLensName: name=' + name);
        log('getLensName: leave');

        return name;
    };

    this.getLensById = function getLensById(lensId) {
        log('getLensById: enter');

        const where = this._allLensIds.indexOf(lensId);

        var theLens = null;

        if (where >= 0) {
            theLens = this._lensDTOs[where];
        }

        log('getLensById: leave');

        return theLens;
    };

    this.getLensesByIds = function getLensesByIds(lensIds) {
        log('getLensesByIds: enter');

        const count = lensIds.length;
        var foundLenses = [];

        for (var zIndex = 0; zIndex < count; zIndex++) {
            var id = lensIds[zIndex];

            var lens = this.getLensById(id);

            if (lens !== null) {
                foundLenses.push(lens);
            }
        }

        log('getLensesByIds: leave');

        return foundLenses;
    };

    this.getLensIdByName = function getLensIdByName(lensName) {
        log('getLensIdByName: enter');

        const where = this._allLensNames.indexOf(lensName);

        var lensId = -1;

        if (where >= 0) {
            const theLens = this._lensDTOs[where];

            lensId = theLens.LensId;
        }

        log('getLensIdByName: lensId=' + lensId);
        log('getLensIdByName: leave');

        return lensId;
    };

    this.getLensIds = function getLensIds() {
        return this._allLensIds;
    };

    this.getLensNames = function getLensNames() {
        return this._allLensNamesSorted;
    };

    this.getLensDTOs = function getLensDTOs() {
        return this._lensDTOs;
    };

    this.getBkLensDTOs = function getBkLensDTOs() {
        log('getBkLensDTOs: enter');

        var bkLenses = [];

        const bkCount = bookmarkStorageUtils.count();
        // how many lenses are bookmarked?

        log('getBkLensDTOs: getBkLensDTOs=' + bkCount);

        if (bkCount < 1) {
            log('getBkLensDTOs: no lenses are bookmarked, so we are done');
            log('getBkLensDTOs: leave');
            return bkLenses;
        }

        bkLenses = this._lensDTOs.filter(lens => bookmarkStorageUtils.isLensBookmarked(lens.LensId));
        // get an array of bookmarked lenses

        log('getBkLensDTOs: bkLenses.length=' + bkLenses.length);
        log('getBkLensDTOs: leave');

        return bkLenses;
    };

    this.getLensDTOsToDisplay = function getLensDTOsToDisplay() {
        log('getLensDTOsToDisplay: enter');

        var theDTOs = [];

        const dispAll = findWhichGroupStateUtils.getFindAll();
        // find all? (as opposed to bookmarked)

        if (dispAll) {
            theDTOs = this.getLensDTOs();
        }
        else {
            theDTOs = this.getBkLensDTOs();
        }

        const hiddenLensIds = lensesToHideStorageUtils.getLensIds();
        // get the ids of the lenses to hide

        const hiddenLensIdsHash = arrayUtils.arrayToHashObject(hiddenLensIds);
        // convert the array to an object we can use as a hash set

        theDTOs = theDTOs.filter(lens => !hiddenLensIdsHash[lens.LensId]);
        // get an array of the lenses that are not hidden

        const foundCount = theDTOs.length;

        log('getLensDTOsToDisplay: foundCount=' + foundCount);
        log('getLensDTOsToDisplay: leave');

        return theDTOs;
    };
}