import { getViewImgFromWidget } from '@ckeditor/ckeditor5-image/src/image/utils';
import { IMAGEMAP_ATTRIBUTES, IMAGEMAP_ELEMENTS, HTML_ATTRIBUTES, HTML_ELEMENTS} from './utils';
import { first } from '@ckeditor/ckeditor5-utils';
import { trimStart } from '../common/qmsCKEditorUtil';

export function dowcastMapAreaAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.MAP_AREAS}:${IMAGEMAP_ELEMENTS.MAP}`, (evt, data, conversionApi) => {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }
            const viewWriter = conversionApi.writer;
            const mapElement = conversionApi.mapper.toViewElement(data.item);
            if(!mapElement){
                return;
            }
            if(data.attributeNewValue != data.attributeOldValue && !!data.attributeNewValue){
                if(mapElement.childCount > 0){
                    Array.from(mapElement.getChildren()).forEach((child) =>{
                        viewWriter.remove(child);
                    });
                }
                const areas = JSON.parse(data.attributeNewValue || '[]');
                if(!!areas && areas.length > 0){
                    areas.forEach(area => {
                        if(area.coords && area.shape){
                            let areaElement = viewWriter.createEmptyElement(HTML_ELEMENTS.AREA, {
                                coords: area.coords,
                                alt: area.alt || '',
                                shape: area.shape || '',
                                href: area.href,
                                target: area.target
                           });
                            viewWriter.insert(viewWriter.createPositionAt(mapElement, 0), areaElement);
                       }
                   });
               }
            }
        });
	};
}

export function dowcastMapNameAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.MAP_NAME}:${IMAGEMAP_ELEMENTS.MAP}`, (evt, data, conversionApi) => {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }
            const viewWriter = conversionApi.writer;
            const mapElement = conversionApi.mapper.toViewElement(data.item);
            if(!mapElement){
                return;
            }
            viewWriter.setAttribute(HTML_ATTRIBUTES.NAME, data.attributeNewValue, mapElement);
            viewWriter.setAttribute(HTML_ATTRIBUTES.ID, data.attributeNewValue, mapElement);
        });
	};
}

export function dowcastMapWidthAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.MAP_WIDTH}:${IMAGEMAP_ELEMENTS.MAP}`, (evt, data, conversionApi) => {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }
            const viewWriter = conversionApi.writer;
            const mapElement = conversionApi.mapper.toViewElement(data.item);
            if(!mapElement){
                return;
            }
            viewWriter.setAttribute(HTML_ATTRIBUTES.WIDTH, data.attributeNewValue || '', mapElement);
        });
	};
}

export function dowcastMapHeightAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.MAP_HEIGHT}:${IMAGEMAP_ELEMENTS.MAP}`, (evt, data, conversionApi) => {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }
            const viewWriter = conversionApi.writer;
            const mapElement = conversionApi.mapper.toViewElement(data.item);
            if(!mapElement){
                return;
            }
            viewWriter.setAttribute(HTML_ATTRIBUTES.HEIGHT, data.attributeNewValue || '', mapElement);
        });
	};
}

export function downcastMapElement() {
	return dispatcher => {
		dispatcher.on(`insert:${IMAGEMAP_ELEMENTS.MAP}`, (evt, data, conversionApi)=> {
            const { consumable, writer, mapper} = conversionApi;
            if (!consumable.consume(data.item, 'insert')) {
                return;
            }
            const viewPosition = mapper.toViewPosition(data.range.start);
            const viewElement = writer.createContainerElement(HTML_ELEMENTS.MAP);
            mapper.bindElements(data.item, viewElement);
            writer.insert(viewPosition, viewElement );
        });
	};
}

export function downcastImageWidthAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.IMAGE_WIDTH}:${IMAGEMAP_ELEMENTS.IMAGE}`, (evt, data, conversionApi) => {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }
            const viewWriter = conversionApi.writer;
            const figure = conversionApi.mapper.toViewElement(data.item);
            const img = getViewImgFromWidget(figure);
            viewWriter.setAttribute(HTML_ATTRIBUTES.WIDTH,  data.attributeNewValue, img);
        });
	};
}


export function downcastImageHeightAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.IMAGE_HEIGHT}:${IMAGEMAP_ELEMENTS.IMAGE}`, (evt, data, conversionApi) => {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }
            const viewWriter = conversionApi.writer;
            const figure = conversionApi.mapper.toViewElement(data.item);
            const img = getViewImgFromWidget(figure);
            viewWriter.setAttribute(HTML_ATTRIBUTES.HEIGHT,  data.attributeNewValue, img);
        });
	};
}


export function downcastImageSavedSrcAttribute(isDataDowncast) {
    const priority = isDataDowncast ? 'highest' : 'normal';
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.IMAGE_SAVED_SRC}:${IMAGEMAP_ELEMENTS.IMAGE}`, (evt, data, conversionApi) => {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }

            const viewWriter = conversionApi.writer;
            const figure = conversionApi.mapper.toViewElement(data.item);
            const img = getViewImgFromWidget(figure);

            if(isDataDowncast == true){
                if(data.item.hasAttribute(data.attributeKey)){
                    const originalSrc = data.item.getAttribute(data.attributeKey);
                    viewWriter.setAttribute(HTML_ATTRIBUTES.SRC, originalSrc, img);
                }
            }
            else {
                viewWriter.setAttribute(HTML_ATTRIBUTES.SAVED_SRC, data.attributeNewValue || '', img);
            }
        },
        {
             priority: priority
        });
	};
}

export function downcastImageMapAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.IMAGE_USE_MAP}:${IMAGEMAP_ELEMENTS.IMAGE}`, (evt, data, conversionApi)=> {
            if (!conversionApi.consumable.consume(data.item, evt.name)) {
                return;
            }

            const viewWriter = conversionApi.writer;
            const figure = conversionApi.mapper.toViewElement(data.item);
            const img = getViewImgFromWidget(figure);

            const newValue = data.attributeNewValue || '';
            const oldValue = data.attributeOldValue || '';

            if(!!newValue){
                viewWriter.setAttribute(HTML_ATTRIBUTES.USE_MAP, data.attributeNewValue, img);
           } else if(!!oldValue){
                viewWriter.removeAttribute(HTML_ATTRIBUTES.USE_MAP, img);
           }
        });
	};
}

export function upcastMapElement() {
	return dispatcher => {
		dispatcher.on(`element:${HTML_ELEMENTS.MAP}`, (evt, data, conversionApi) => {
			const viewMap = data.viewItem;
            const currentPosition = data.modelCursor;
            const modelWriter = conversionApi.writer;

            // Do not convert if this is not an map.
            if (!conversionApi.consumable.test(data.viewItem, {name: true})) {
                return;
           }

			const name = viewMap.getAttribute(HTML_ATTRIBUTES.NAME);
			 // Do not convert if image element is missing 'name' attribute.
			if (!name) {
                return;
           }

            const areas = [];
            if(viewMap.childCount > 0){
                for (const child of Array.from(viewMap.getChildren())) {
                    try {
                        if (child.getAttribute() < 5) throw -1;
                        const check = child.getAttribute(HTML_ATTRIBUTES.COORDS);
                        if (!check) throw -1;
                    }
                    catch(err){
                        continue;
                    }
                    
                    let area = {};
                    area[HTML_ATTRIBUTES.COORDS] = child.getAttribute(HTML_ATTRIBUTES.COORDS);
                    area[HTML_ATTRIBUTES.HREF] = child.getAttribute(HTML_ATTRIBUTES.HREF);
                    area[HTML_ATTRIBUTES.ALT] = child.getAttribute(HTML_ATTRIBUTES.ALT) || '';
                    area[HTML_ATTRIBUTES.SHAPE] = child.getAttribute(HTML_ATTRIBUTES.SHAPE) || '';
                    area[HTML_ATTRIBUTES.TARGET] = child.getAttribute(HTML_ATTRIBUTES.TARGET);
                    areas.push(area);
               }
           }

            const width = viewMap.getAttribute(HTML_ATTRIBUTES.WIDTH);
            const height = viewMap.getAttribute(HTML_ATTRIBUTES.HEIGHT);
            let attrs = {};
            attrs[IMAGEMAP_ATTRIBUTES.MAP_NAME] = name;
            attrs[IMAGEMAP_ATTRIBUTES.MAP_AREAS] = JSON.stringify(areas);
            attrs[IMAGEMAP_ATTRIBUTES.MAP_WIDTH] = width;
            attrs[IMAGEMAP_ATTRIBUTES.MAP_HEIGHT] = height;
            const modelMap = modelWriter.createElement(IMAGEMAP_ELEMENTS.MAP, attrs);

            //TODO: Insert map element as a direct child of root
            modelWriter.insert(modelMap, currentPosition);
            conversionApi.convertChildren(viewMap, modelMap);
            conversionApi.updateConversionResult(modelMap, data);
		},
        {
            priority: 'high'
       });
	};
}


export function upcastImageMapAttribute() {
	return dispatcher => {
		dispatcher.on(`element:${HTML_ELEMENTS.IMAGE}`, (evt, data, conversionApi) => {
            const {consumable, writer} = conversionApi;
            const viewImage = data.viewItem;

            // Do not convert if the `usemap` attribute  was already converted.
			if (!consumable.consume(viewImage, {attributes: [HTML_ATTRIBUTES.USE_MAP]})) {
				return;
			}

			const usemap = viewImage.getAttribute(HTML_ATTRIBUTES.USE_MAP);
			 // Do not convert if image element is missing `usemap` attribute
			if (!usemap) {
				return;
			}

            const modelImage = first(data.modelRange.getItems());
            // When image wasn't successfully converted then finish conversion.
            if (!modelImage) {
                return;
           }

            if (modelImage.is('element', IMAGEMAP_ELEMENTS.IMAGE)) {
                const mapName =  trimStart(usemap, '#');
				writer.setAttribute(IMAGEMAP_ATTRIBUTES.IMAGE_USE_MAP, '#' + mapName, modelImage);
			}
		},
        {
            priority: 'low'
        });
	};
}


export function upcastImageSavedSrcAttribute() {
	return dispatcher => {
		dispatcher.on(`element:${HTML_ELEMENTS.IMAGE}`, (evt, data, conversionApi) => {
            const {consumable, writer} = conversionApi;
            const viewImage = data.viewItem;

            // Do not convert if the `usemap` attribute  was already converted.
			if (!consumable.consume(viewImage, {attributes: [HTML_ATTRIBUTES.SAVED_SRC]})) {
				return;
			}

			const originalSrc = viewImage.getAttribute(HTML_ATTRIBUTES.SAVED_SRC);

			 // Do not convert if image element is missing `usemap` attribute
			if (!originalSrc) {
				return;
			}

            const modelImage = first(data.modelRange.getItems());
            // When image wasn't successfully converted then finish conversion.
            if (!modelImage) {
                return;
           }

            if (modelImage.is('element', IMAGEMAP_ELEMENTS.IMAGE)) {
				writer.setAttribute(IMAGEMAP_ATTRIBUTES.IMAGE_SAVED_SRC, originalSrc || '', modelImage);
			}

		},
        {
            priority: 'low'
        });
	};
}


export function upcastImageWidthAttribute() {
	return dispatcher => {
		dispatcher.on(`element:${HTML_ELEMENTS.IMAGE}`, (evt, data, conversionApi) => {
            const {consumable, writer} = conversionApi;
            const viewImage = data.viewItem;

            // Do not convert if the `usemap` attribute  was already converted.
			if (!consumable.consume(viewImage, {attributes: [HTML_ATTRIBUTES.WIDTH]})) {
				return;
			}

			const width = viewImage.getAttribute(HTML_ATTRIBUTES.WIDTH);

			 // Do not convert if image element is missing `usemap` attribute
			if (!width) {
				return;
			}

            const modelImage = first(data.modelRange.getItems());
            // When image wasn't successfully converted then finish conversion.
            if (!modelImage) {
                return;
            }

            if (modelImage.is('element', IMAGEMAP_ELEMENTS.IMAGE)) {
				writer.setAttribute(IMAGEMAP_ATTRIBUTES.IMAGE_WIDTH, width, modelImage);
			}
		},
        {
            priority: 'low'
        });
	};
}



export function upcastImageHeightAttribute() {
	return dispatcher => {
		dispatcher.on(`element:${HTML_ELEMENTS.IMAGE}`, (evt, data, conversionApi) => {
            const {consumable, writer} = conversionApi;
            const viewImage = data.viewItem;

            // Do not convert if the `usemap` attribute  was already converted.
			if (!consumable.consume(viewImage, {attributes: [HTML_ATTRIBUTES.HEIGHT]})) {
				return;
			}

			const height = viewImage.getAttribute(HTML_ATTRIBUTES.HEIGHT);

			 // Do not convert if image element is missing `usemap` attribute
			if (!height) {
				return;
			}

            const modelImage = first(data.modelRange.getItems());
            // When image wasn't successfully converted then finish conversion.
            if (!modelImage) {
                return;
            }

            if (modelImage.is('element', IMAGEMAP_ELEMENTS.IMAGE)) {
				writer.setAttribute(IMAGEMAP_ATTRIBUTES.IMAGE_HEIGHT, height, modelImage);
			}
		},
        {
            priority: 'low'
        });
	};
}

export function downcastImagePluginAttribute() {
	return dispatcher => {
		dispatcher.on(`attribute:${IMAGEMAP_ATTRIBUTES.IMAGE_SRC}:${IMAGEMAP_ELEMENTS.IMAGE}`, (evt, data, conversionApi)=> {
       
            const viewWriter = conversionApi.writer;
            const figure = conversionApi.mapper.toViewElement(data.item);
            const img = getViewImgFromWidget(figure);
            const altAttribute = data.item.getAttribute('alt') || '';
            
            const classes = altAttribute.split('#');
            const className = classes.length > 0 ? classes[0] : '';
            const attributes = {};

            switch (className) {
                case 'bpmn':
                    attributes['class'] = 'bpmn-chart-entity';
                    attributes['data-charttype'] = className;
                    break;
                case 'flowchart':
                    attributes['class'] = 'flow-chart-entity';
                    attributes['data-charttype'] = 'flow';
                    break;
            
                default:
                    attributes['class'] = '';
                    attributes['data-charttype'] = '';
                    break;
            }

            viewWriter.setAttribute('class', attributes['class'], img);
            viewWriter.setAttribute('data-charttype', attributes['data-charttype'], img);
        });
	};
}