function createPage(casper) {
    /*eslint max-statements:0*/
    "use strict";
    var mainPage = require('webpage').create();
    mainPage.isPopup = false;

    var onClosing = function onClosing(closedPopup) {
        if (closedPopup.isPopup) {
            if (casper.page !== null && casper.page.id === closedPopup.id) {
                casper.page = casper.mainPage;
            }
            casper.popups.clean();
            casper.emit('popup.closed', closedPopup);
        } else {
            casper.page = null;
            casper.emit('page.closed', closedPopup);
        }
    };

    var onLoadFinished = function onLoadFinished(status) {
        this.windowNameBackUp = this.windowName;
        /*eslint max-statements:0*/
        if (status !== "success") {
            casper.emit('load.failed', {
                status:      status,
                http_status: casper.currentHTTPStatus,
                url:         this.url
            });
            var message = 'Loading resource failed with status=' + status;
            if (casper.currentHTTPStatus) {
                message += f(' (HTTP %d)', casper.currentHTTPStatus);
            }
            message += ': ' + casper.requestUrl;
            casper.log(message, "warning");
            casper.navigationRequested = false;
            this.browserInitializing = false;
            if (utils.isFunction(casper.options.onLoadError)) {
                casper.options.onLoadError.call(casper, casper, casper.requestUrl, status);
            }
        }

        var index = 0, currentPage = casper.page;
        casper.page = this;
        this.switchToMainFrame();
        for (var l = this.frames.length; index < l ; index++) {
            try {
                casper.switchToChildFrame(this.frames[index]);
            } catch(e) {
                break;
            }
        }
        this.framesReloaded = this.frames.slice(index);
        this.frames = this.frames.slice(0, index);

        if (this.framesReloaded.length !== 0) {
            casper.emit('frame.reset', this.framesReloaded);
        }
        casper.page = currentPage;

        // local client scripts
        casper.injectClientScripts(this);
        // remote client scripts
        casper.includeRemoteScripts(this);
        // Client-side utils injection
        casper.injectClientUtils(this);
        // history
        casper.history.push(casper.getCurrentUrl());
        casper.emit('load.finished', status);
        this.loadInProgress = false;
        if (this.isPopup) {
            casper.emit('popup.loaded', this);
        } else {
            casper.emit('page.loaded', this);
        }
    };

    var onLoadStarted = function onLoadStarted() {
        // in some case, there is no navigation requested event, so
        // be sure that browserInitializing is false to not block checkStep()
        this.browserInitializing = false;
        this.loadInProgress = true;
        casper.emit('load.started');
    };

    var onNavigationRequested = function onNavigationRequested(url, type, willNavigate, isMainFrame) {
        casper.log(f('Navigation requested: url=%s, type=%s, willNavigate=%s, isMainFrame=%s',
                     url, type, willNavigate, isMainFrame), "debug");
        this.browserInitializing = false;
        casper.page.switchToMainFrame();
        if (isMainFrame && casper.requestUrl !== url) {
            var currentUrl = casper.requestUrl;
            var newUrl = url;
            var pos = currentUrl.indexOf('#');
            if (pos !== -1) {
                currentUrl = currentUrl.substring(0, pos);
            }
            pos = newUrl.indexOf('#');
            if (pos !== -1) {
                newUrl = newUrl.substring(0, pos);
            }
            // for URLs that are only different by their hash part
            // or if navigation locked (willNavigate == false)
            // don't turn navigationRequested to true, because
            // there will not be loadStarted, loadFinished events
            // so it could cause issues (for exemple, checkStep that
            // do no execute the next step -> infinite loop on checkStep)
            if (willNavigate && currentUrl !== newUrl) {
                casper.navigationRequested = true;
            }
            if (willNavigate) {
                casper.requestUrl = url;
            }
        }
        casper.emit('navigation.requested', url, type, willNavigate, isMainFrame);
    };
    
    var onPageCreated = function onPageCreated(page) {
        page.isPopup = (typeof page.isPopup === "undefined") ? true : false;
        page.id = new Date().getTime();
        page.browserInitializing = false;
        page.loadInProgress = false; 
        page.windowNameBackUp = page.windowName;
        page.frames = [];
        page.framesReloaded = [];
        page.context = {
            "x": 0,
            "y": 0
        };

        page.settings.loadImagesValue = page.settings.loadImages;
        Object.defineProperty(page.settings,'loadImages', {
            get: function() { 
                return page.settings.loadImagesValue;
            },
            set: function(newValue) {
                page.settings.loadImagesValue = newValue;
                if (typeof page.clearMemoryCache === 'function') {
                    page.clearMemoryCache();
                }
            }
        });

        page.onClosing =  function() {
            var p = page;
            return function() {
                return onClosing.apply(p, arguments);
            };
        }();
        page.onLoadFinished = function() {
            var p = page;
            return function() {
                return onLoadFinished.apply(p, arguments);
            };
        }();
        page.onLoadStarted = function() {
            var p = page;
            return function() {
                return onLoadStarted.apply(p, arguments);
            };
        }();
        page.onNavigationRequested = function() {
            var p = page;
            return function() {
                return onNavigationRequested.apply(p, arguments);
            };
        }();
        page.onPageCreated = onPageCreated;

        page.onAlert = function onAlert(message) {
            casper.log('[alert] ' + message, "info", "remote");
            casper.emit('remote.alert', message);
            if (utils.isFunction(casper.options.onAlert)) {
                casper.options.onAlert.call(casper, casper, message);
            }
        };
        page.onConfirm = function onConfirm(message) {
            if ('page.confirm' in casper._filters) {
                return casper.filter('page.confirm', message);
            }
            return true;
        };
        page.onConsoleMessage = function onConsoleMessage(msg) {
            // client utils casper console message
            var consoleTest = /^\[casper\.echo\]\s?([\s\S]*)/.exec(msg);
            if (consoleTest && consoleTest.length === 2) {
                casper.echo(consoleTest[1]);
                return; // don't trigger remote.message event for these
            }
            // client utils log messages
            var logLevel = "info",
                logTest = /^\[casper:(\w+)\]\s?([\s\S]*)/m.exec(msg);
            if (logTest && logTest.length === 3) {
                logLevel = logTest[1];
                msg = logTest[2];
                casper.log(msg, logLevel, "remote");
            } else {
                casper.emit('remote.message', msg);
            }
        };

        page.onCallback = function onCallback(data){
            casper.emit('remote.callback', data);
        };
        page.onError = function onError(msg, trace) {
            casper.emit('page.error', msg, trace);
        };
        page.onFilePicker = function onFilePicker(olderFile) {
            return casper.filter('page.filePicker', olderFile);
        };
        page.onFileDownload = function onFileDownload(url, data) {
            if ('fileDownload' in casper._filters) {
                return casper.filter('fileDownload', url, data);
            }
            casper.log("File to download : aborted", "debug");
            return null;
        };
        page.onFileDownloadError = function onFileDownloadError(error) {
            return casper.emit('fileDownloadError', error);
        };
        page.onInitialized = function onInitialized() {
            casper.emit('page.initialized', page);
            if (utils.isFunction(casper.options.onPageInitialized)) {
                casper.log("Post-configuring WebPage instance", "debug");
                casper.options.onPageInitialized.call(casper, page);
            }
        };
        page.onLongRunningScript = function onLongRunningScript(message) {
            casper.emit('remote.longRunningScript', page, message);
        };
        page.onPrompt = function onPrompt(message, value) {
            return casper.filter('page.prompt', message, value);
        };
        page.onResourceReceived = function onResourceReceived(resource) {
            http.augmentResponse(resource);
            casper.emit('resource.received', resource);
            if (utils.isFunction(casper.options.onResourceReceived)) {
                casper.options.onResourceReceived.call(casper, casper, resource);
            }
            casper.handleReceivedResource(resource);
        };
        page.onResourceRequested = function onResourceRequested(requestData, request) {
            casper.emit('resource.requested', requestData, request);
            var checkUrl = ((phantom.casperEngine === 'phantomjs' && utils.ltVersion(phantom.version, '2.1.0')) ||
                       (phantom.casperEngine === 'slimerjs' && utils.ltVersion(slimer.version, '0.10.0'))) ? utils.decodeUrl(requestData.url) : requestData.url;
            if (checkUrl === casper.requestUrl) {
                casper.emit('page.resource.requested', requestData, request);
            }
            if (utils.isFunction(casper.options.onResourceRequested)) {
                casper.options.onResourceRequested.call(casper, casper, requestData, request);
            }
            casper.requestData[requestData.id] = requestData;
        };
        page.onResourceError = function onResourceError(resourceError) {
            casper.emit('resource.error', resourceError);
        };
        page.onResourceTimeout = function onResourceTimeout(resourceError) {
            casper.emit('resource.timeout', resourceError);
        };
        page.onUrlChanged= function onUrlChanged(url) {
            casper.log(f('url changed to "%s"', url), "debug");
            casper.navigationRequested= false;
            casper.emit('url.changed', url);
        };

        if (page.isPopup) {
            casper.emit('popup.created', page);
            if (casper.options.pageSettings.userAgent !== defaultUserAgent) {
                page.customHeaders = {"User-Agent": casper.options.pageSettings.userAgent};
            }
            page.settings = utils.mergeObjects(page.settings, casper.options.pageSettings);
            if (utils.isClipRect(casper.options.clipRect)) {
                page.clipRect = casper.options.clipRect;
            }
            if (utils.isObject(casper.options.viewportSize)) {
                page.viewportSize = casper.options.viewportSize;
            }
            casper.popups.push(page);
        } else {
            casper.emit('page.created', page);
        }
    };
    onPageCreated(mainPage);
    return mainPage;
}
Creates a new WebPage instance for Casper use.

@param  Casper  casper  A Casper instance
@return WebPage