// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.dataprofiler.core.ui.wizard.indicator;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TableColumn;
import org.talend.dataprofiler.core.ImageLib;
import org.talend.dataprofiler.core.pattern.PatternToExcelEnum;
import org.talend.dq.helper.FileUtils;
import org.talend.dq.helper.UDIHelper;
import com.talend.csv.CSVReader;
/**
* CsvFileTableViewer is a table viewer for preview a simple csv file.
*/
public class CsvFileTableViewer extends Composite {
private Logger log = Logger.getLogger(CsvFileTableViewer.class);
private static final char CURRENT_SEPARATOR = '\t';
private boolean useTextQualifier = true;
private static final Image WARN_IMG = ImageLib.getImage(ImageLib.LEVEL_WARNING);
private CSVReader reader;
private TableViewer viewer;
private boolean quotesError = false;
private boolean emptyError = true;
private boolean hasEmptyRow = false;
private boolean hasPatternHeaders = false;
/**
* DOC yyi CsvFileTableViewer class global comment. Detailled comment
*
* FIXME this inner class should be static. Confirm and fix the error.
*/
class ViewContentProvider implements IStructuredContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
hasEmptyRow = false;
emptyError = true;
}
public void dispose() {
}
public Object[] getElements(Object parent) {
CSVReader csvReader = (CSVReader) parent;
List<Object> rows = new ArrayList<Object>();
try {
while (csvReader.readNext()) {
rows.add(csvReader.getValues());
}
} catch (IOException e) {
log.error(e, e);
}
List<Object> rows2 = new ArrayList<Object>();
for (Object obj : rows) {
if (obj instanceof String[]) {
String[] strs = (String[]) obj;
for (int i = 0; i < strs.length; ++i) {
strs[i] = strs[i].replaceAll(UDIHelper.PARA_SEPARATE_1, UDIHelper.PARA_SEPARATE_1_DISPLAY).replaceAll(
UDIHelper.PARA_SEPARATE_2, UDIHelper.PARA_SEPARATE_2_DISPLAY);
}
rows2.add(strs);
} else {
rows2.add(obj);
}
}
return rows2.toArray(new Object[rows2.size()]);
}
}
/**
* DOC yyi CsvFileTableViewer class global comment. Detailled comment
*/
class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
public String getColumnText(Object obj, int index) {
String[] values = (String[]) obj;
checkEmptyError(values);
return index < values.length ? values[index] : null;
}
/**
* DOC talend Comment method "checkEmptyError".
*
* @param obj
* @param index
*/
private void checkEmptyError(String[] values) {
if (hasEmptyRow) {
return;
}
try {
String[] headers = reader.getHeaders();
if (values.length < headers.length) {
String errorRow = "";
for (String value : values) {
errorRow += value;
}
log.error("The size of values is less than size of headers.When check the row for: " + errorRow); //$NON-NLS-1$
return;
}
for (int index = 0; index < headers.length; index++) {
String header = headers[index];
String value = values[index];
if (isNotEmpty(value)) {
if (isRegEx(index)) {
emptyError = false;
} else if (PatternToExcelEnum.Category.getLiteral().equalsIgnoreCase(header)) {
emptyError = false;
} else if (PatternToExcelEnum.JavaClassName.getLiteral().equalsIgnoreCase(header)) {
emptyError = false;
} else if (PatternToExcelEnum.JavaJarPath.getLiteral().equalsIgnoreCase(header)) {
emptyError = false;
}
}
if (isLastOne(index, headers.length)) {
if (emptyError) {
hasEmptyRow = true;
}
}
}
} catch (IOException e) {
log.error(e, e);
}
}
/**
* judge the method whether is empty
*
* @param input
* @return true when input is null or length is 0 after remove quote
*/
private boolean isNotEmpty(String input) {
String value = trimQuote(input);
return value != null && !(value.isEmpty());
}
/**
* DOC talend Comment method "isLastOne".
*
* @return
*/
private boolean isLastOne(int index, int length) {
return index == (length - 1);
}
public Image getColumnImage(Object obj, int index) {
String[] values = (String[]) obj;
return index < values.length ? getImage(values[index], index) : null;
}
public Image getImage(Object obj, int index) {
if (!checkQuoteMarks(obj.toString(), index)) {
quotesError = true;
return WARN_IMG;
} else {
return null;
}
}
}
public CsvFileTableViewer(final Composite parent, int style) {
super(parent, style);
setLayout(new GridLayout());
createView(this);
viewer.setInput(reader);
}
private void createHeader(String[] headers) {
int columnCount = headers.length;
TableColumn[] columns = viewer.getTable().getColumns();
for (TableColumn column : columns) {
column.dispose();
}
for (int i = 0; i < columnCount; i++) {
TableColumn tableColumn = new TableColumn(viewer.getTable(), SWT.NONE);
tableColumn.setText(headers[i]);
tableColumn.pack();
}
}
private void createView(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
GridData data = new GridData(GridData.FILL_BOTH);
data.heightHint = 100;
viewer.getTable().setLayoutData(data);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.getTable().setHeaderVisible(true);
viewer.getTable().setLinesVisible(true);
}
private boolean checkQuoteMarks(String text, int index) {
if (0 == text.length()) {
return true;
}
if (isRegEx(index)) {
String trimQuote = trimQuote(text);
if (0 == trimQuote.length()) {
return true;
} else if ('\'' == trimQuote.charAt(0) && '\'' == trimQuote.charAt(trimQuote.length() - 1)) {
return true;
} else if ('\'' != trimQuote.charAt(0) && '\'' != trimQuote.charAt(trimQuote.length() - 1)) {
return true;
} else {
return false;
}
}
if ('\"' == text.charAt(0) && '\"' == text.charAt(text.length() - 1)) {
return true;
}
if ('\"' != text.charAt(0) && '\"' != text.charAt(text.length() - 1)) {
return true;
}
return false;
}
/**
* the column which index is "index" is a register expression
*
* @param index
* @return
*/
private boolean isRegEx(int index) {
try {
String[] headers = reader.getHeaders();
String header = headers[index];
if (PatternToExcelEnum.DB2Regexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.MySQLRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.OracleRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.PostgreSQLRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.SQLServerRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.SybaseRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.IngresRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.InformixRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.NETEZZARegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.SQLite3Regexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.Teradata.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.JavaRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.Access.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.AS400.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.Hive.getLiteral().equalsIgnoreCase(header)) {
return true;
} else if (PatternToExcelEnum.AllDBRegexp.getLiteral().equalsIgnoreCase(header)) {
return true;
}
} catch (IOException e) {
log.error(e, e);
}
return false;
}
private boolean checkFileHeader(String[] headers) {
List<String> patternEnum = new ArrayList<String>();
for (PatternToExcelEnum tmpEnum : PatternToExcelEnum.values()) {
patternEnum.add(tmpEnum.getLiteral());
}
for (String header : headers) {
if (!patternEnum.contains(trimQuote(header))) {
return false;
}
}
return true;
}
private String trimQuote(String text) {
if (text.length() < 2) {
return text;
}
int beginLen = 0;
int endLen = text.length();
if ('\"' == text.charAt(beginLen) && '\"' == text.charAt(endLen - 1)) {
return text.substring(1, endLen - 1);
}
return text;
}
/**
* set a csv file.
*
* @param csvFile
* @return whether the file be loaded.
*/
public boolean setCsvFile(File csvFile) {
quotesError = false;
hasPatternHeaders = false;
try {
if (useTextQualifier) {
reader = FileUtils.createCSVReader(csvFile, FileUtils.TEXT_QUAL, FileUtils.TEXT_QUAL);
} else {
reader = FileUtils.createCSVReader(csvFile, FileUtils.QUOTECHAR_NOTVALID, FileUtils.TEXT_QUAL);
}
reader.setSkipEmptyRecords(true);
reader.readHeaders();
String[] headers = reader.getHeaders();
hasPatternHeaders = checkFileHeader(headers);
createHeader(headers);
} catch (IOException e1) {
e1.printStackTrace();
}
viewer.setInput(reader);
return true;
}
/**
* Returns <code>true</code> if the file contains a patterns header.
*
* @return whether the file contains a patterns header.
*/
public boolean isHeadersInvalid() {
return !hasPatternHeaders;
}
/**
* Returns <code>true</code> if Use Text Qualifier.
*
* @return whether Use Text Qualifier
*/
public boolean isUseTextQualifier() {
return useTextQualifier;
}
/**
* Sets the csv reader use text qualifier if the argument is <code>true</code>.
*
* @param useTextQualifier
*/
public void setUseTextQualifier(boolean useTextQualifier) {
this.useTextQualifier = useTextQualifier;
}
/**
* Returns <code>true</code> if the file contains quotes error value.
*
* @return
*/
public boolean isQuotesError() {
return quotesError;
}
public boolean isEmptyDefinition() {
return this.hasEmptyRow;
}
}