/**
 * CodeDropz Uploader
 * Copyright 2018 Glen Mongaya
 * CodeDrop Drag&Drop Uploader
 * @version 1.3.9.8
 * @author CodeDropz, Glen Don L. Mongaya
 * @license The MIT License (MIT)
 */

// CodeDropz Drag and Drop Plugin
(function() {

    const CodeDropz_Uploader = function( settings ){

        // Generate & check nonce
        const form = document.querySelector('form.wpcf7-form');
        if( form ) {
            const data = new FormData();
            data.append('action', '_wpcf7_check_nonce');
            data.append('_ajax_nonce', dnd_cf7_uploader.ajax_nonce );
            fetch(dnd_cf7_uploader.ajax_url, { method: 'POST', body: data })
            .then(res => res.json())
            .then(({ data, success }) => success && (dnd_cf7_uploader.ajax_nonce = data))
            .catch(console.error)
		}

		// Generate random string
		const generateRandomFolder = function( length = 20 ) {
			const bytes = new Uint8Array(16);
			crypto.getRandomValues(bytes);
			bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
			bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10
			const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
			return hex.replace(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/, '$1-$2-$3-$4-$5');
		}

        // Parent input file type
        var input = this;

        // Define default options
        const defaultOptions = {
            handler: input,
            color: '#000',
            background: '',
            server_max_error: 'Uploaded file exceeds the maximum upload size of your server.',
            max_file: input.dataset.max ? parseInt( input.dataset.max ) : 10, // default 10
            max_upload_size: input.dataset.limit ? input.dataset.limit : '10485760', // should be a bytes it's (5MB)
            supported_type: input.dataset.type ? input.dataset.type : 'jpg|jpeg|JPG|png|gif|pdf|doc|docx|ppt|pptx|odt|avi|ogg|m4a|mov|mp3|mp4|mpg|wav|wmv|xls',
            text: 'Drag & Drop Files Here',
            separator: 'or',
            button_text: 'Browse Files',
            on_success: '',
        };

        // Merge options with default options
        const options = Object.assign({}, defaultOptions, settings);

        // Get storage name
        var dataStorageName = input.dataset.name + '_count_files';

        // File Counter
        localStorage.setItem( dataStorageName, 1);

		// Get unique id from local storage.
		var sessionID = dnd_upload_cf7_unique_id();
		var folderToken = sessionID ? localStorage.getItem( 'dnd_cf7_token_' + sessionID ) : null;

		// Unique upload session_id & token
		if ( ! sessionID || ! folderToken ) {
			sessionID   = generateRandomFolder();
			folderToken = generateRandomFolder(); // Generate folder token if not exists.
			localStorage.setItem( 'dnd_wpcf7_session_id', JSON.stringify({ value: sessionID, savedAt: Date.now() }) );
			localStorage.setItem( 'dnd_cf7_token_' + sessionID, folderToken );
		}

        // Template Container
        const cdropz_template = `
            <div class="codedropz-upload-handler">
                <div class="codedropz-upload-container">
                <div class="codedropz-upload-inner">
                    <${dnd_cf7_uploader.drag_n_drop_upload.tag}>${options.text}</${dnd_cf7_uploader.drag_n_drop_upload.tag}>
                    <span>${options.separator}</span>
                    <div class="codedropz-btn-wrap"><a class="cd-upload-btn" href="#">${options.button_text}</a></div>
                </div>
                </div>
                <span class="dnd-upload-counter"><span>0</span> ${dnd_cf7_uploader.dnd_text_counter} ${parseInt(options.max_file)}</span>
            </div>
        `;

        // Wrap input fields
        const wrapper = document.createElement('div');

        // Begin to wrap upload fields
        wrapper.classList.add('codedropz-upload-wrapper');
        options.handler.parentNode.insertBefore(wrapper, options.handler);
        wrapper.appendChild(options.handler);

        // Remove special character
        options.supported_type = options.supported_type.replace(/[^a-zA-Z0-9| ]/g, "");

        // Element Handler
        const form_handler = options.handler.closest('form');
        const options_handler = options.handler.closest('.codedropz-upload-wrapper');
        const btnOBJ = form_handler.querySelector('input[type="submit"], button[type="submit"]');

        // Append Format
        options.handler.insertAdjacentHTML('afterend', cdropz_template);

        // preventing the unwanted behaviours
        ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach(function(eventName) {
            options_handler.querySelector('.codedropz-upload-handler').addEventListener(eventName, function(e) {
                e.preventDefault();
                e.stopPropagation();
            });
        });

        // dragover and dragenter - add class
        ['dragover', 'dragenter'].forEach(function(eventName) {
            options_handler.querySelector('.codedropz-upload-handler').addEventListener(eventName, function(e) {
                options_handler.querySelector('.codedropz-upload-handler').classList.add('codedropz-dragover');
            });
        });

        // dragleave dragend drop - remove class
        ['dragleave', 'dragend', 'drop'].forEach(function(eventName){
            options_handler.querySelector('.codedropz-upload-handler').addEventListener(eventName, function(e) {
                options_handler.querySelector('.codedropz-upload-handler').classList.remove('codedropz-dragover');
            });
        });

        // Browse button clicked
        options_handler.querySelector('.cd-upload-btn').addEventListener('click', function(e){
            // stops the default action of an element from happening
            e.preventDefault();

            // Reset value
            options.handler.value = null;

            // Click input type[file] element
            options.handler.click();
        });

        // when dropping files
        options_handler.querySelector('.codedropz-upload-handler').addEventListener('drop', function(event) {
            // Run the uploader
            DND_Setup_Uploader(event.dataTransfer.files, 'drop');
        });

        // Trigger when input type[file] is click/changed
        options.handler.addEventListener('change', function(e) {
            // Run the uploader
            DND_Setup_Uploader(this.files, 'click');
        });

        // Remove accept attribute on mobile devices
        if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
            input.removeAttribute('accept');
        }

        // Setup Uploader
        var DND_Setup_Uploader = function( files, action ) {

            // make sure we have files
            if (files.length == 0 ) return;

            // gathering the form data
            var formData = new FormData();

            // Append file
            //formData.append('supported_type', options.supported_type ); @note : removed due Vulnerability
            formData.append('action', 'dnd_codedropz_upload' );
            formData.append('type', action );
            formData.append('security', dnd_cf7_uploader.ajax_nonce );

            // CF7 - upload field name & cf7 id
            formData.append('form_id', input.dataset.id);
            formData.append('upload_name', input.dataset.name);
			formData.append('upload_folder', sessionID );
			formData.append('token', folderToken ); // append folder token.

            // black list file types
            /*if( input.hasAttribute('data-black-list') ){
                formData.append('blacklist-types', input.dataset.blackList);
            }*/

            // remove has error
            const errorHandler           = options.handler.querySelector('.has-error');
			const CodeDropzUploadElement = options_handler.querySelector('.codedropz-upload-handler');

            if (errorHandler) {
                errorHandler.remove();
            }

            // Loop files
            for (const file of files) {

                // Reset upload file type
                if( typeof formData.delete !== 'undefined' ) {
                    formData.delete('upload-file');
                }

                // Limit file upload
                if( Number( localStorage.getItem(dataStorageName) ) > options.max_file ) {
                    var hasErrorMsg = options_handler.querySelector('span.has-error-msg');
                    if (!hasErrorMsg) {
                        var err_msg = dnd_cf7_uploader.drag_n_drop_upload.max_file_limit;
                        var errorMsgEl = document.createElement('span');
                        errorMsgEl.className = 'has-error-msg';
                        errorMsgEl.textContent = err_msg.replace('%count%', options.max_file);
						CodeDropzUploadElement.parentNode.insertBefore( errorMsgEl, CodeDropzUploadElement.nextSibling );
                    }
                    return false;
                }

                // Create progress bar
                const progressBarID = CodeDropz_Object.createProgressBar( file );
                var has_error = false;

                // File size limit - validation
                if (file.size > options.max_upload_size) {
                    const parentProgressBar = document.getElementById(progressBarID);
                    const errorSpan = document.createElement('span');
                    errorSpan.classList.add('has-error');
                    errorSpan.textContent = dnd_cf7_uploader.drag_n_drop_upload.large_file;
                    parentProgressBar.querySelector('.dnd-upload-details').appendChild(errorSpan);
                    has_error = true;
                }

                // Validate file type
                regex_type = new RegExp("(.*?)\.("+ options.supported_type +")$");
                if ( has_error === false && !( regex_type.test( file.name.toLowerCase() ) ) ) {
                    document.querySelector('#' + progressBarID + ' .dnd-upload-details').insertAdjacentHTML('beforeend', '<span class="has-error">' + dnd_cf7_uploader.drag_n_drop_upload.inavalid_type + '</span>');
                    has_error = true;
                }

                // Increment count
                localStorage.setItem( dataStorageName, ( Number( localStorage.getItem( dataStorageName ) ) + 1 ) );

                // Make sure there's no error
                if( has_error === false ) {

                    // Append file
                    formData.append('upload-file', file );

                    // Process ajax upload
                    var xhr = new XMLHttpRequest();

                    // Get progress bar element [changes 2026]
                    let progressBar = document.getElementById( progressBarID );
                    let progressElement = progressBar.querySelector('.dnd-progress-bar');
                    let detailsElement = progressBar.querySelector('.dnd-upload-details');
                    let submitButton = form_handler.querySelector('input[type="submit"], button[type="submit"]');

                    xhr.open(form_handler.getAttribute('method'), options.ajax_url);
                    xhr.onreadystatechange = function() {
                        if (this.readyState === 4) {
                            if (this.status === 200) {
                                var response = JSON.parse(this.responseText);
                                if (response.success) {

                                    // Complete the progress bar
                                    CodeDropz_Object.setProgressBar(progressBarID, 100);

                                    // Callback on success
                                    if (typeof options.on_success === "function") {
                                        options.on_success.call(this, input, progressBarID, response);
                                    }

                                } else {
									const filesCounter   = ( Number( localStorage.getItem(dataStorageName) ) - 1 );
									const counterElement = input.closest('.codedropz-upload-wrapper').querySelector('.dnd-upload-counter span');

                                    progressElement.remove();
                                    detailsElement.insertAdjacentHTML('beforeend', '<span class="has-error">'+ response.data +'</span>');
                                    if( submitButton ){
                                        //submitButton.classList.remove('disabled'); @remove since 1.3.9.8
                                        submitButton.removeAttribute('disabled');
                                    }
                                    progressBar.classList.remove('in-progress');

									// Update counter
									counterElement.textContent = filesCounter;
                                }
                            } else {
                                progressElement.remove();
                                detailsElement.insertAdjacentHTML('beforeend', '<span class="has-error">'+ options.server_max_error +'</span>');
                                if( submitButton ){
                                    //submitButton.classList.remove('disabled'); @remove since 1.3.9.8
                                    submitButton.removeAttribute('disabled');
                                }
                                progressBar.classList.remove('in-progress');
                            }
                        }
                    };
                    xhr.upload.addEventListener("progress", function(event){
                        if ( event.lengthComputable ) {

                            var percentComplete = ( event.loaded / event.total );
                            var percentage = parseInt( percentComplete * 100 );

                            // Make progress on the loading
                            CodeDropz_Object.setProgressBar( progressBarID, percentage - 1 );
                        }
                    }, false);

                    xhr.send(formData);

                }
            }

        }
        // End of Uploader function

        // CodeDropz object and functions
        var CodeDropz_Object = {

            // Create progress bar
            createProgressBar : function( file ) {

                // Setup progress bar variable
                var upload_handler = options_handler.querySelector('.codedropz-upload-handler');
                var generated_ID = 'dnd-file-' + Math.random().toString(36).substr(2, 9);

                // Setup progressbar elements
                var fileDetails = `
                    <div class="dnd-upload-image">
                        <span class="file"></span>
                    </div>
                    <div class="dnd-upload-details">
                        <span class="name"><span>${file.name}</span><em>(${CodeDropz_Object.bytesToSize(file.size)})</em></span>
                        <a href="#" title="${dnd_cf7_uploader.drag_n_drop_upload.delete.title}" class="remove-file" data-storage="${dataStorageName}">
                        <span class="dnd-icon-remove"></span>
                        </a>
                        <span class="dnd-progress-bar"><span></span></span>
                    </div>
                `;

                // Create new element and insert after upload_handler
                var statusElement = document.createElement('div');
                statusElement.id = generated_ID;
                statusElement.className = 'dnd-upload-status';
                statusElement.innerHTML = fileDetails;
                upload_handler.parentNode.insertBefore(statusElement, upload_handler.nextSibling);

                return generated_ID;

            },

            // Process progressbar ( Animate progress )
            setProgressBar : function( progressBarID, percent ) {

                const progressBar = document.getElementById( progressBarID );
                const statusBar = progressBar.querySelector('.dnd-progress-bar');

                //console.log(statusbar);
                if (statusBar) {

                    // Disable submit button
                    if( btnOBJ ){
                        CodeDropz_Object.disableBtn(btnOBJ);
                    }

                    // Compute Progress bar
                    let progress_width = percent * statusBar.offsetWidth / 100;

                    // Set status bar in-progress
                    progressBar.classList.add('in-progress');

                    if (percent == 100) {
                        statusBar.querySelector('span').style.width = '100%';
                        statusBar.querySelector('span').textContent = `${percent}% `;
                    } else {
                        statusBar.querySelector('span').style.width = progress_width + 'px';
                        statusBar.querySelector('span').textContent = `${percent}% `;
                    }

                    if (percent == 100) {
                        progressBar.classList.add('complete');
                        progressBar.classList.remove('in-progress');
                    }
                }
                return false;

            },

            // Size Conversion
            bytesToSize : function( bytes ) {

                if( bytes === 0 )
                    return '0';

                kBytes = (bytes / 1024);
                fileSize = ( kBytes >= 1024 ? ( kBytes / 1024 ).toFixed(2) + 'MB' : kBytes.toFixed(2) + 'KB' );

                return fileSize;
            },

            // Disable button
            disableBtn : function( BtnOJB ) {
                if( BtnOJB  ) {
                    //BtnOJB.classList.add('disabled'); @remove since 1.3.9.8
                    BtnOJB.disabled = true;
                }
            }
        };

	} // end fn.function

    // Remove File
    document.addEventListener("click", function(e) {
        if( !e.target.classList.contains("dnd-icon-remove") ) return;

		e.preventDefault();
        var _self             = e.target,
            _dnd_status       = _self.closest(".dnd-upload-status"),
            _parent_wrap      = _self.closest(".codedropz-upload-wrapper"),
            removeStorageData = _self.parentElement.getAttribute("data-storage"),
            storageCount      = Number(localStorage.getItem(removeStorageData)),
			sessionId         = dnd_upload_cf7_unique_id();

        // Direct remove the file if there's any error.
        if (_dnd_status.classList.contains("in-progress") || _dnd_status.querySelector(".has-error")) {
            _dnd_status.remove();
            localStorage.setItem(removeStorageData, storageCount - 1);
			_parent_wrap.querySelector(".dnd-upload-counter span").textContent = Number(localStorage.getItem(removeStorageData)) - 1;
            return false;
        }

        // Change text Status
        _self.classList.add("deleting");
        _self.textContent = dnd_cf7_uploader.drag_n_drop_upload.delete.text + "...";

        // Request ajax image delete
        var xhr = new XMLHttpRequest();
        xhr.open("POST", dnd_cf7_uploader.ajax_url);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.onload = function() {
            if (this.status === 200) {
                var response = JSON.parse(this.responseText);
                if (response.success) {

                    // Reduce file count and status bar element.
                    _dnd_status.remove();
                    localStorage.setItem(removeStorageData, storageCount - 1);

                    // Remove error msg
                    if ( _parent_wrap.querySelectorAll(".dnd-upload-status").length <= 1 ){
                        if( _parent_wrap.querySelector(".has-error-msg") ){
                            _parent_wrap.querySelector(".has-error-msg").remove();
                        }
                    }

                    // Update Counter
                    _parent_wrap.querySelector(".dnd-upload-counter span").textContent = Number(localStorage.getItem(removeStorageData)) - 1;
                } else {
					const upload_details = _dnd_status.querySelector('.dnd-upload-details');
					if ( upload_details ) {
						const errorMsg = document.createElement('span');
						errorMsg.classList.add('has-error-msg');
						errorMsg.textContent = response.data;
						upload_details.appendChild( errorMsg );
					}
				}
            }
        };

        xhr.send(
            "path=" + _dnd_status.querySelector('input[type="hidden"]').value +
            "&action=dnd_codedropz_upload_delete" +
            "&security=" + dnd_cf7_uploader.ajax_nonce +
			"&upload_folder=" + sessionId +
			"&token=" + localStorage.getItem( 'dnd_cf7_token_' + sessionId ),
        );

        document.querySelectorAll(".has-error-msg").forEach(function(el) {
            el.remove();
        });

    });

    // Attach CodeDropz_Uploader to HTMLElement prototype
    HTMLElement.prototype.CodeDropz_Uploader = CodeDropz_Uploader;

})();
// END: CodeDropz Uploader function

// Custom JS hook event
var dnd_upload_cf7_event = function(target, name, data) {
	// Create a custom event with the specified name and data
	var event = new CustomEvent('dnd_upload_cf7_' + name, {
		bubbles: true,
		detail: data
	});
	target.dispatchEvent(event);
}

// Get unique id. (reset after 24hours)
function dnd_upload_cf7_unique_id() {
	const item = localStorage.getItem('dnd_wpcf7_session_id');
	if ( ! item ) {
		return null;
	}

	// Parse item
	const data = JSON.parse( item );

	// Expired? then remove value from localstorage.
	if ( Date.now() - data.savedAt > ( 24 * 60 * 60 * 1000 ) ) {
		localStorage.removeItem('dnd_cf7_token_' + data.value ); // delete token
		localStorage.removeItem('dnd_wpcf7_session_id');         // delete session id
		return null;
	}

	return data.value;
}

// BEGIN: initialize upload
document.addEventListener('DOMContentLoaded', function() {

	// Fires when an Ajax form submission has completed successfully, and mail has been sent.
    document.addEventListener( 'wpcf7mailsent', function( event ) {

        // Get form
        const form = event.target;

        // Get input type file element
        var inputFile = form.querySelectorAll('.wpcf7-drag-n-drop-file');
        var status = form.querySelectorAll('.dnd-upload-status');
        var counter = form.querySelector('.dnd-upload-counter span');
        var error = form.querySelectorAll('span.has-error-msg');

        // Reset upload list for multiple fields
        if ( inputFile.length > 0 ) {
            inputFile.forEach( function(input) {
                localStorage.setItem( input.getAttribute('data-name') + '_count_files', 1 ); // Reset file counts
            });
        }

        // Remove status / progress bar
        if (status) {
            status.forEach(function(statEl){
                statEl.remove();
            });
        }

        if (counter) {
            counter.textContent = '0';
        }

        if (error) {
            error.forEach(function(errEl){
                errEl.remove();
            });
        }

    }, false );

	window.initDragDrop = function () {

		// Get text object options/settings from localize script
		var TextOJB = dnd_cf7_uploader.drag_n_drop_upload;
        var fileUpload = document.querySelectorAll('.wpcf7-drag-n-drop-file');

        fileUpload.forEach(function(Upload) {

            // Support Multiple Fileds
            Upload.CodeDropz_Uploader({
                'color': '#fff',
                'ajax_url': dnd_cf7_uploader.ajax_url,
                'text': TextOJB.text,
                'separator': TextOJB.or_separator,
                'button_text': TextOJB.browse,
                'server_max_error': TextOJB.server_max_error,
                'on_success': function(input, progressBar, response) {

                    // Progressbar Object
                    var progressDetails = document.querySelector('.codedropz-upload-wrapper #' + progressBar);
                    var form = input.closest('form');
                    var span = form.querySelector('.wpcf7-acceptance');
                    var checkboxInput = ( span ? span.querySelector('input[type="checkbox"]') : '' );

                    // Remove 'required' error message
                    const requiredMessage = input.closest('.codedropz-upload-wrapper').nextElementSibling;
                    if( requiredMessage && requiredMessage.classList.contains('wpcf7-not-valid-tip') ){
                        requiredMessage.remove();
                    }

                    // If it's complete remove disabled attribute in button
                    if ( ( span && span.classList.contains('optional') ) || ! span || checkboxInput.checked || form.classList.contains('wpcf7-acceptance-as-validation')) {
						setTimeout(function(){
                            const submitButton = form.querySelector('button[type=submit], input[type=submit]');
                            if( submitButton ){
								//submitButton.classList.remove('disabled'); @remove since 1.3.9.8
                                submitButton.removeAttribute('disabled');
                            }
                        }, 1);
                    }

                    // Append hidden input field
                    var detailsElement = progressDetails.querySelector('.dnd-upload-details');
                    var inputHTML = '<span><input type="hidden" name="' + input.dataset.name + '[]" value="' + response.data.path + '/' + response.data.file + '"></span>';
                    detailsElement.insertAdjacentHTML('beforeend', inputHTML);

                    // Update counter
                    var filesCounter = ( Number( localStorage.getItem( input.dataset.name + '_count_files' ) ) - 1);
                    var counterElement = input.closest('.codedropz-upload-wrapper').querySelector('.dnd-upload-counter span');
                    counterElement.textContent = filesCounter;

					// Add custom event
					dnd_upload_cf7_event( progressDetails, 'success', response );
                }
            });

        });

	}

	window.initDragDrop();

	// Usage: Custom js hook after success upload
	/*document.addEventListener( 'dnd_upload_cf7_success', function( event ) {
		console.log(event.detail);
	});*/

});