/*jshint node: true, jasmine: true */
/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

// these tests are meant to be executed by Cordova Medic Appium runner
// you can find it here: https://github.com/apache/cordova-medic/
// it is not necessary to do a full CI setup to run these tests
// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-camera"

'use strict';

var wdHelper = require('../helpers/wdHelper');
var wd = wdHelper.getWD();
var isDevice = global.DEVICE;
var cameraConstants = require('../../www/CameraConstants');
var cameraHelper = require('../helpers/cameraHelper');
var screenshotHelper = require('../helpers/screenshotHelper');

var MINUTE = 60 * 1000;
var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW_1';

describe('Camera tests iOS.', function () {

    var driver;
    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    var startingMessage = 'Ready for action!';

    function win() {
        expect(true).toBe(true);
    }

    function fail(error) {
        screenshotHelper.saveScreenshot(driver);
        if (error && error.message) {
            console.log('An error occured: ' + error.message);
            expect(true).toFailWithMessage(error.message);
            throw error.message;
        }
        if (error) {
            console.log('Failed expectation: ' + error);
            expect(true).toFailWithMessage(error);
            throw error;
        }
        // no message provided :(
        expect(true).toBe(false);
        throw 'An error without description occured';
    }

    // generates test specs by combining all the specified options
    // you can add more options to test more scenarios
    function generateSpecs() {
        var sourceTypes = [
                cameraConstants.PictureSourceType.CAMERA,
                cameraConstants.PictureSourceType.PHOTOLIBRARY
            ],
            destinationTypes = cameraConstants.DestinationType,
            encodingTypes = [
                cameraConstants.EncodingType.JPEG,
                cameraConstants.EncodingType.PNG
            ],
            allowEditOptions = [
                true,
                false
            ];

        return cameraHelper.generateSpecs(sourceTypes, destinationTypes, encodingTypes, allowEditOptions);
    }

    function getPicture(options, cancelCamera, skipUiInteractions) {
        if (!options) {
            options = {};
        }
        var command = "navigator.camera.getPicture(function (result) { document.getElementById('info').innerHTML = 'Success: ' + result.slice(0, 100); }, " +
                      "function (err) { document.getElementById('info').innerHTML = 'ERROR: ' + err; }," + JSON.stringify(options) + ");";
        return driver
            .sleep(2000)
            .context(webviewContext)
            .execute(command)
            .sleep(5000)
            .context('NATIVE_APP')
            .then(function () {
                if (skipUiInteractions) {
                    return;
                }
                if (options.hasOwnProperty('sourceType') && options.sourceType === cameraConstants.PictureSourceType.PHOTOLIBRARY) {
                    return driver
                        .elementByName('Camera Roll')
                        .click()
                        .elementByXPath('//UIACollectionCell')
                        .click()
                        .then(function () {
                            if (options.hasOwnProperty('allowEdit') && options.allowEdit === true) {
                                return driver
                                    .elementByName('Use')
                                    .click();
                            }
                            return driver;
                        });
                }
                if (options.hasOwnProperty('sourceType') && options.sourceType === cameraConstants.PictureSourceType.SAVEDPHOTOALBUM) {
                    return driver
                        .elementByXPath('//UIACollectionCell')
                        .click()
                        .then(function () {
                            if (options.hasOwnProperty('allowEdit') && options.allowEdit === true) {
                                return driver
                                    .elementByName('Use')
                                    .click();
                            }
                            return driver;
                        });
                }
                if (cancelCamera) {
                    return driver
                        .elementByName('Cancel')
                        .click();
                }
                return driver
                    .elementByName('PhotoCapture')
                    .click()
                    .elementByName('Use Photo')
                    .click();
            })
            .sleep(3000);
    }

    function enterTest() {
        return driver
            .contexts(function (err, contexts) {
                if (err) {
                    fail(err);
                } else {
                    // if WEBVIEW context is available, use it
                    // if not, use NATIVE_APP
                    webviewContext = contexts[contexts.length - 1];
                }
            })
            .then(function () {
                return driver
                    .context(webviewContext);
            })
            .fail(fail)
            .elementById('info')
            .fail(function () {
                // unknown starting page: no 'info' div
                // adding it manually
                return driver
                    .execute('var info = document.createElement("div"); ' +
                             'info.id = "info"' +
                             'document.body.appendChild(info);')
                    .fail(fail);
            })
            .execute('document.getElementById("info").innerHTML = "' + startingMessage + '";')
            .fail(fail);
    }

    function checkPicture(shouldLoad) {
        return driver
            .contexts(function (err, contexts) {
                // if WEBVIEW context is available, use it
                // if not, use NATIVE_APP
                webviewContext = contexts[contexts.length - 1];
            })
            .context(webviewContext)
            .elementById('info')
            .getAttribute('innerHTML')
            .then(function (html) {
                if (html.indexOf(startingMessage) >= 0) {
                    expect(true).toFailWithMessage('No callback was fired');
                } else if (shouldLoad) {
                    expect(html.length).toBeGreaterThan(0);
                    if (html.indexOf('ERROR') >= 0) {
                        expect(true).toFailWithMessage(html);
                    }
                } else {
                    if (html.indexOf('ERROR') === -1) {
                        expect(true).toFailWithMessage('Unexpected success callback with result: ' + html);
                    }
                    expect(html.indexOf('ERROR')).toBe(0);
                }
            })
            .context('NATIVE_APP');
    }

    function runCombinedSpec(spec) {
        return enterTest()
            .then(function () {
                return getPicture(spec.options);
            })
            .then(function () {
                return checkPicture(true);
            })
            .then(win, fail);
    }

    beforeEach(function () {
        jasmine.addMatchers({
            toFailWithMessage : function () {
                return {
                    compare: function (actual, msg) {
                        console.log('Failing with message: ' + msg);
                        var result = {
                            pass: false,
                            message: msg
                        };
                        return result;
                    }
                };
            }
        });
    });

    it('camera.ui.util Configuring driver and starting a session', function (done) {
        driver = wdHelper.getDriver('iOS', done);
    }, 3 * MINUTE);

    describe('Specs.', function () {
        // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY
        it('camera.ui.spec.1 Selecting only videos', function (done) {
            var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
                            mediaType: cameraConstants.MediaType.VIDEO };
            enterTest()
                .then(function () { return getPicture(options, false, true); }) // skip ui unteractions
                .sleep(5000)
                .elementByName('Videos')
                .then(win, fail)
                .elementByName('Cancel')
                .click()
                .finally(done);
        }, 3 * MINUTE);

        // getPicture(), then dismiss
        // wait for the error callback to bee called
        it('camera.ui.spec.2 Dismissing the camera', function (done) {
            // camera is not available on iOS simulator
            if (!isDevice) {
                pending();
            }
            var options = { sourceType: cameraConstants.PictureSourceType.CAMERA };
            enterTest()
                .then(function () {
                    return getPicture(options, true);
                })
                .then(function () {
                    return checkPicture(false);
                })
                .elementByXPath('//UIAStaticText[contains(@label,"no image selected")]')
                .then(function () {
                    return checkPicture(false);
                }, fail)
                .finally(done);
        }, 3 * MINUTE);

        // combine various options for getPicture()
        generateSpecs().forEach(function (spec) {
            it('camera.ui.spec.3.' + spec.id + ' Combining options', function (done) {
                // camera is not available on iOS simulator
                if (!isDevice) {
                    pending();
                }
                runCombinedSpec(spec).then(done);
            }, 3 * MINUTE);
        });

    });

    it('camera.ui.util.4 Destroy the session', function (done) {
        driver.quit(done);
    }, 10000);
});
