/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/postem/trunk/postem-app/src/java/org/sakaiproject/tool/postem/CSV.java $
* $Id: CSV.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 The Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.
*
**********************************************************************************/
package org.sakaiproject.tool.postem;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.zip.DataFormatException;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import org.apache.myfaces.shared_impl.util.MessageUtils;
public class CSV {
private List contents;
private List headers;
private List students;
private String csv;
private static boolean truncatingWarningDisplayed;
public static final char COMMA_DELIM = ',';
public static final char TAB_DELIM = '\t';
public static final int MAX_COL_LENGTH = 2000;
// private boolean withHeaders = true;
public CSV(String csv, boolean withHeader) throws DataFormatException {
truncatingWarningDisplayed = false;
contents = retrieveContents(csv, COMMA_DELIM);
headers = retrieveHeaders(contents);
students = retrieveStudents(contents, withHeader);
this.csv = csv;
}
public CSV(String csv, boolean withHeader, char delimiter) throws DataFormatException {
truncatingWarningDisplayed = false;
contents = retrieveContents(csv, delimiter);
headers = retrieveHeaders(contents);
students = retrieveStudents(contents, withHeader);
this.csv = csv;
}
public CSV(List contents, boolean withHeader) {
truncatingWarningDisplayed = false;
headers = retrieveHeaders(contents);
students = retrieveStudents(contents, withHeader);
csv = createFromContents(contents);
this.contents = contents;
}
public List getHeaders() {
return headers;
}
public List getStudents() {
return students;
}
public List getStudentUsernames() {
List usernames = new ArrayList();
Iterator studentIter = students.iterator();
while (studentIter.hasNext()) {
List s1 = (List) studentIter.next();
String usr = ((String) s1.get(0)).trim();
usernames.add(usr);
}
return usernames;
}
public String getCsv() {
return csv;
}
public static String createFromContents(List rows) {
StringBuilder csv = new StringBuilder();
Iterator riter = rows.iterator();
while (riter.hasNext()) {
Iterator citer = ((List) riter.next()).iterator();
while (citer.hasNext()) {
String current = (String) citer.next();
if (current == null) {
current = "";
}
current = current.replaceAll("\"", "\"\"");
csv.append("\"");
csv.append(current);
csv.append("\"");
if (citer.hasNext()) {
csv.append(",");
}
}
if (riter.hasNext()) {
csv.append("\r\n");
}
}
return csv.toString();
}
public static List retrieveContents(String csv, char delimiter) throws DataFormatException {
List all = new ArrayList();
List current = new ArrayList();
StringBuilder it = new StringBuilder();
boolean inQuotes = false;
int length = csv.length();
for (int ii = 0; ii < length; ii++) {
if (inQuotes) {
if (ii == length - 1) {
current.add((it.length() == 0) ? " " : it.toString());
all.add(current);
break;
}
if (csv.charAt(ii) == '"') {
if (ii < length - 1 && csv.charAt(ii + 1) == '"') {
it.append("\"");
ii++;
} else {
inQuotes = false;
}
} else {
it.append(csv.charAt(ii));
}
} else {
if (ii == length - 1 && csv.charAt(ii) != '\n'
&& csv.charAt(ii) != '\r') {
if (csv.charAt(ii) == delimiter) {
it = truncateIt(it);
current.add((it.length() == 0) ? " " : it.toString());
current.add("");
} else {
it.append(csv.charAt(ii));
it = truncateIt(it);
current.add((it.length() == 0) ? " " : it.toString());
}
all.add(current);
break;
}
if (csv.charAt(ii) == delimiter) {
it = truncateIt(it);
current.add((it.length() == 0) ? " " : it.toString());
it = new StringBuilder();
// this line would trim leading spaces per the spec, but not trailing
// ones.
// we don't care about it so much anyways, since the info
// will be output in a web context
// csv = csv.trim();
} else if (csv.charAt(ii) == '\r' || csv.charAt(ii) == '\n') {
if (ii < length - 1 && csv.charAt(ii + 1) == '\n') {
ii++;
}
it = truncateIt(it);
current.add((it.length() == 0) ? " " : it.toString());
it = new StringBuilder();
all.add(current);
current = new ArrayList();
} else if (csv.charAt(ii) == '"') {
inQuotes = true;
} else {
it.append(csv.charAt(ii));
}
}
}
// we want to identify the row with the most columns and then append blank columns until all the rows
// are the same length
int finalNumCols = 0;
for (int i=0; i < all.size(); i++) {
if(((List)all.get(i)).size() > finalNumCols) {
finalNumCols = ((List)all.get(i)).size();
}
}
// make sure all of the rows have the same number of cols as the longest row
for (int j=0; j < all.size(); j++) {
while(((List)all.get(j)).size() < finalNumCols) {
((List)all.get(j)).add(" ");
}
}
return all;
}
public static List retrieveHeaders(List rows) {
if (rows == null || rows.size() == 0) {
return null;
}
return (List) rows.get(0);
}
public static List retrieveStudents(List rows, boolean withHeader) {
List headers = retrieveHeaders(rows);
List results = new ArrayList(rows);
if (withHeader == true) {
results.remove(0);
}
return results;
}
public static int determineColumns(String csv, char delimiter) {
int total = 0;
boolean inQuotes = false;
int length = csv.length();
for (int ii = 0; ii < length; ii++) {
if (inQuotes) {
if (csv.charAt(ii) == '"') {
if (ii < length - 1 && csv.charAt(ii + 1) == '"') {
ii++;
} else {
inQuotes = false;
}
}
} else {
if (csv.charAt(ii) == delimiter) {
total++;
} else if (csv.charAt(ii) == '\r' || csv.charAt(ii) == '\n') {
break;
} else if (csv.charAt(ii) == '"') {
inQuotes = true;
}
}
}
total++;
return total;
}
/**
* we need to truncate any data greater than MAX_COL_LENGTH chars for the db
* @param buffer
* @return
*/
private static StringBuilder truncateIt(StringBuilder buffer)
{
if (buffer.length() > MAX_COL_LENGTH) // truncate text longer than MAX_COL_LENGTH
{
String truncatedString = buffer.substring(0, MAX_COL_LENGTH);
buffer = new StringBuilder();
buffer.append(truncatedString);
if (!truncatingWarningDisplayed) {
truncatingWarningDisplayed = true;
FacesContext.getCurrentInstance().addMessage(
null,
MessageUtils.getMessage(FacesMessage.SEVERITY_INFO,
"data_truncated_warning", (new Object[] { new Integer(MAX_COL_LENGTH) }), FacesContext
.getCurrentInstance()));
}
}
return buffer;
}
}