org.sakaiproject.tool.gradebook.ui.SpreadsheetUploadBean.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.tool.gradebook.ui.SpreadsheetUploadBean.java

Source

/*******************************************************************************
 * Copyright (c) 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.gradebook.ui;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.custom.fileupload.UploadedFile;
import org.apache.poi.hssf.OldExcelFormatException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.content.api.ContentResource;
import org.sakaiproject.content.api.FilePickerHelper;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.cover.EntityManager;
import org.sakaiproject.exception.ServerOverloadException;
import org.sakaiproject.jsf.util.JsfTool;
import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord;
import org.sakaiproject.section.api.coursemanagement.User;
import org.sakaiproject.section.api.facade.Role;
import org.sakaiproject.service.gradebook.shared.ConflictingAssignmentNameException;
import org.sakaiproject.service.gradebook.shared.ConflictingSpreadsheetNameException;
import org.sakaiproject.tool.api.Tool;
import org.sakaiproject.tool.api.ToolSession;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.tool.gradebook.Assignment;
import org.sakaiproject.tool.gradebook.AssignmentGradeRecord;
import org.sakaiproject.tool.gradebook.Category;
import org.sakaiproject.tool.gradebook.Comment;
import org.sakaiproject.tool.gradebook.Gradebook;
import org.sakaiproject.tool.gradebook.LetterGradePercentMapping;
import org.sakaiproject.tool.gradebook.jsf.FacesUtil;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.Validator;

public class SpreadsheetUploadBean extends GradebookDependentBean implements Serializable {

    private String title;
    private UploadedFile upFile;
    private String pickedFileReference;
    private String pickedFileDesc;
    private static final Log logger = LogFactory.getLog(SpreadsheetUploadBean.class);
    private Spreadsheet spreadsheet;
    private Map rosterMap;
    private List assignmentList;
    private List studentRows;
    private List assignmentHeaders;
    private Map selectedAssignment;
    private List assignmentColumnSelectItems;
    private boolean saved = false;
    private String columnCount;
    private String rowCount;
    private boolean hasUnknownUser;
    private boolean hasUnknownAssignments;
    private Long spreadsheetId;
    private Map scores;
    private Assignment assignment;
    private Long assignmentId;
    private Integer selectedCommentsColumnId = 0;
    private List categoriesSelectList;
    private List extraCreditCategories;
    private Boolean extraCreditCatSelected = Boolean.FALSE;
    private Category assignmentCategory;
    private String selectedCategory;
    private Gradebook localGradebook;
    private StringBuilder externallyMaintainedImportMsg;
    private UIComponent uploadButton;
    private String csvDelimiter;
    private NumberFormat numberFormat;
    private boolean selectedCategoryDropsScores;
    private String date_entry_format_description;

    // Used for bulk upload of gradebook items
    // Holds list of unknown user ids
    private List unknownUsers = new ArrayList();
    private List unknownAssignments = new ArrayList();

    private static final String POINTS_POSSIBLE_STRING = "export_points_possible";
    private static final String CUMULATIVE_GRADE_STRING = "roster_course_grade_column_name";
    private static final String IMPORT_SUCCESS_STRING = "import_entire_success";
    private static final String IMPORT_SOME_SUCCESS_STRING = "import_entire_some_success";
    private static final String IMPORT_NO_CHANGES = "import_entire_no_changes";
    private static final String IMPORT_ASSIGNMENT_NOTSUPPORTED = "import_assignment_entire_notsupported";
    private static final String IMPORT_ASSIGNMENT_NEG_VALUE = "import_assignment_entire_negative_score";
    private static final int MAX_FILE_PICKER_UPLOADS = 1;
    static final String PICKED_FILE_REFERENCE = "pickedFileReference";
    static final String PICKED_FILE_DESC = "pickedFileDesc";
    static final String IMPORT_TITLE = "gradebookImportTitle";

    public static final String UNASSIGNED_CATEGORY = "unassigned";

    /**
     * Property set via sakai.properties to limit the file size allowed for spreadsheet
     * uploads. This property is in MB and defaults to 1 MB.
     */
    public static final String PROPERTY_FILE_SIZE_MAX = "gradebook.upload.max";

    /**
     * The default max file size, in MB, for a spreadsheet upload.
     */
    public static final int FILE_SIZE_DEFAULT = 1;

    /**
     * If an upload contains more than the number of students in the class plus
     * this value, the upload will fail.
     */
    private static final int MAX_NUM_ROWS_OVER_CLASS_SIZE = 50;

    private String pageName;

    public SpreadsheetUploadBean() {

    }

    public void init() {

        localGradebook = getGradebook();

        initializeRosterMap();

        if (assignment == null) {
            if (assignmentId != null) {
                assignment = getGradebookManager().getAssignment(assignmentId);
            }
            if (assignment == null) {
                // it is a new assignment
                assignment = new Assignment();
                assignment.setReleased(true);
            }
        }

        // initialization; shouldn't enter here after category drop down changes
        if (assignmentCategory == null
                && !getLocalizedString("cat_unassigned").equalsIgnoreCase(selectedCategory)) {
            Category assignCategory = assignment.getCategory();
            if (assignCategory != null) {
                selectedCategory = assignCategory.getId().toString();
                selectedCategoryDropsScores = assignCategory.isDropScores();
                assignCategory.setAssignmentList(retrieveCategoryAssignmentList(assignCategory));
                assignmentCategory = assignCategory;
            } else {
                selectedCategory = getLocalizedString("cat_unassigned");
            }
        }

        if (selectedCategory == null)
            selectedCategory = AssignmentBean.UNASSIGNED_CATEGORY;
        categoriesSelectList = new ArrayList();
        //create comma seperate string representation of the list of EC categories
        extraCreditCategories = new ArrayList();
        // The first choice is always "Unassigned"
        categoriesSelectList.add(
                new SelectItem(AssignmentBean.UNASSIGNED_CATEGORY, FacesUtil.getLocalizedString("cat_unassigned")));
        List gbCategories = getViewableCategories();
        if (gbCategories != null && gbCategories.size() > 0) {
            Iterator catIter = gbCategories.iterator();
            while (catIter.hasNext()) {
                Category cat = (Category) catIter.next();
                categoriesSelectList.add(new SelectItem(cat.getId().toString(), cat.getName()));
                if (cat.isExtraCredit()) {
                    extraCreditCategories.add(cat.getId().toString());
                }
            }
        }
        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, (new ResourceLoader()).getLocale());
        date_entry_format_description = ((SimpleDateFormat) df).toPattern();

    }

    private void initializeRosterMap() {
        //initialize rosteMap which is map of displayid and user objects
        rosterMap = new HashMap();
        List enrollments = new ArrayList(findMatchingEnrollmentsForAllItems(null, null).keySet());
        if (logger.isDebugEnabled())
            logger.debug("enrollment size " + enrollments.size());

        Iterator iter;
        iter = enrollments.iterator();
        while (iter.hasNext()) {
            EnrollmentRecord enr;
            enr = (EnrollmentRecord) iter.next();
            if (logger.isDebugEnabled())
                logger.debug(
                        "displayid " + enr.getUser().getDisplayId() + "  userid " + enr.getUser().getUserUid());
            rosterMap.put(enr.getUser().getDisplayId().toLowerCase(), enr.getUser());
        }
    }

    public String getTitle() {
        if (title == null || "".equals(title)) {
            // check the session attribute
            ToolSession session = SessionManager.getCurrentToolSession();
            if (session.getAttribute(IMPORT_TITLE) != null) {
                title = (String) session.getAttribute(IMPORT_TITLE);
            }
        }
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public UploadedFile getUpFile() {
        return upFile;
    }

    public void setUpFile(UploadedFile upFile) {
        if (logger.isDebugEnabled())
            logger.debug("upload file name " + upFile.getName());
        this.upFile = upFile;
    }

    public Spreadsheet getSpreadsheet() {
        return spreadsheet;
    }

    public void setSpreadsheet(Spreadsheet spreadsheet) {
        this.spreadsheet = spreadsheet;
    }

    public Map getRosterMap() {
        return rosterMap;
    }

    public void setRosterMap(Map rosterMap) {
        this.rosterMap = rosterMap;
    }

    public Long getSpreadsheetId() {
        return spreadsheetId;
    }

    public void setSpreadsheetId(Long spreadsheetId) {
        this.spreadsheetId = spreadsheetId;
    }

    public List getSpreadsheets() {
        this.setPageName("spreadsheetListing");
        return getGradebookManager().getSpreadsheets(getGradebookId());
    }

    public String deleteItem() {
        return "spreadsheetRemove";
    }

    public List getAssignmentList() {
        return assignmentList;
    }

    public void setAssignmentList(List assignmentList) {
        this.assignmentList = assignmentList;
    }

    public List getStudentRows() {
        return studentRows;
    }

    public void setStudentRows(List studentRows) {
        this.studentRows = studentRows;
    }

    public List getAssignmentHeaders() {
        return assignmentHeaders;
    }

    public void setAssignmentHeaders(List assignmentHeaders) {
        this.assignmentHeaders = assignmentHeaders;
    }

    public Map getSelectedAssignment() {
        return selectedAssignment;
    }

    public void setSelectedAssignment(Map selectedAssignment) {
        this.selectedAssignment = selectedAssignment;
    }

    public List getAssignmentColumnSelectItems() {
        return assignmentColumnSelectItems;
    }

    public void setAssignmentColumnSelectItems(List assignmentColumnSelectItems) {
        this.assignmentColumnSelectItems = assignmentColumnSelectItems;
    }

    public boolean isSaved() {
        return saved;
    }

    public void setSaved(boolean saved) {
        this.saved = saved;
    }

    /**
     * Returns formatted string with count of assignments imported (columns - 1 {student name})
     */
    public String getVerifyColumnCount() {
        final int intColumnCount = new Integer(columnCount == null ? "0" : columnCount).intValue() - 1;
        return FacesUtil.getLocalizedString("import_verify_column_count",
                new String[] { Integer.toString(intColumnCount) });
    }

    public String getColumnCount() {
        return FacesUtil.getLocalizedString("upload_preview_column_count", new String[] { columnCount });
    }

    public void setColumnCount(String columnCount) {
        this.columnCount = columnCount;
    }

    /**
     * Returns formatted string with count of number of students imported
     * Added points possible row so need to subtract one from count
     */
    public String getVerifyRowCount() {
        return FacesUtil.getLocalizedString("import_verify_row_count", new String[] { rowCount });
    }

    public String getRowCount() {
        return FacesUtil.getLocalizedString("upload_preview_row_count", new String[] { rowCount });
    }

    public void setRowCount(String rowCount) {
        this.rowCount = rowCount;
    }

    public String getRowStyles() {
        StringBuilder sb = new StringBuilder();
        if (studentRows != null) {
            for (Iterator iter = studentRows.iterator(); iter.hasNext();) {
                SpreadsheetRow row = (SpreadsheetRow) iter.next();
                if (row.isKnown()) {
                    sb.append("internal,");
                } else {
                    sb.append("external,");
                }
            }
        }
        if (logger.isDebugEnabled())
            logger.debug(sb.toString());
        return sb.toString();
    }

    /**
     * Returns List of unknown user names
     */
    public boolean getHasUnknownUser() {
        return hasUnknownUser;
    }

    public Map getScores() {
        return scores;
    }

    public void setScores(Map scores) {
        this.scores = scores;
    }

    public Assignment getAssignment() {
        return assignment;
    }

    public void setAssignment(Assignment assignment) {
        this.assignment = assignment;
    }

    public Long getAssignmentId() {
        return assignmentId;
    }

    public void setAssignmentId(Long assignmentId) {
        this.assignmentId = assignmentId;
    }

    /**
     * Returns list of unknown users
     */
    public List getUnknownUsers() {
        return unknownUsers;
    }

    /**
     * Sets the list of unknown users
     */
    public void setUnknownUsers(List unknownUsers) {
        this.unknownUsers = unknownUsers;
    }

    public boolean isHasUnknownAssignments() {
        return hasUnknownAssignments;
    }

    public void setHasUnknownAssignments(boolean hasUnknownAssignments) {
        this.hasUnknownAssignments = hasUnknownAssignments;
    }

    public List getUnknownAssignments() {
        return unknownAssignments;
    }

    public void setUnknownAssignments(List unknownAssignments) {
        this.unknownAssignments = unknownAssignments;
    }

    /**
     * Returns the count of unknown users
     */
    public int getUnknownSize() {
        this.setPageName("spreadsheetAll");
        return unknownUsers.size();
    }

    public List getCategoriesSelectList() {
        return categoriesSelectList;
    }

    public String getSelectedCategory() {
        return selectedCategory;
    }

    public void setSelectedCategory(String selectedCategory) {
        this.selectedCategory = selectedCategory;
    }

    public Gradebook getLocalGradebook() {
        return localGradebook;
    }

    /**
    * For retaining the pageName variable throughout import process
    */
    public String getPageName() {
        return pageName;
    }

    public void setPageName(String pageName) {
        this.pageName = pageName;
    }

    public String getExternallyMaintainedImportMsg() {
        if (externallyMaintainedImportMsg == null || externallyMaintainedImportMsg.length() < 1)
            return null;

        return externallyMaintainedImportMsg.toString();
    }

    /**
     * Returns the Category associated with selectedCategory
     * If unassigned or not found, returns null
     * @return
     */
    private Category retrieveSelectedCategory() {
        Long catId = null;
        Category category = null;

        if (selectedCategory != null && !selectedCategory.equals(AssignmentBean.UNASSIGNED_CATEGORY)) {
            try {
                catId = new Long(selectedCategory);
            } catch (Exception e) {
                catId = null;
            }

            if (catId != null) {
                // check to make sure there is a corresponding category
                category = getGradebookManager().getCategory(catId);

                //populate assignments list
                category.setAssignmentList(retrieveCategoryAssignmentList(category));
            }
        }

        return category;
    }

    private List retrieveCategoryAssignmentList(Category cat) {
        List assignmentsToUpdate = new ArrayList();
        if (cat != null) {
            List assignments = cat.getAssignmentList();
            if (cat.isDropScores() && (assignments == null || assignments.size() == 0)) { // don't populate, if assignments are already in category (to improve performance)
                assignments = getGradebookManager().getAssignmentsForCategory(cat.getId());

                // only include assignments which are not adjustments must not update adjustment item pointsPossible
                for (Object o : assignments) {
                    if (o instanceof Assignment) {
                        Assignment assignment = (Assignment) o;
                        if (!Assignment.item_type_adjustment.equals(assignment.getItemType())) {
                            assignmentsToUpdate.add(assignment);
                        }
                    }
                }
            }
        }
        return assignmentsToUpdate;
    }

    //view file from db
    public String viewItem() {

        if (rosterMap == null) {
            init();
        }

        if (logger.isDebugEnabled())
            logger.debug("loading viewItem()");

        org.sakaiproject.tool.gradebook.Spreadsheet sp = getGradebookManager().getSpreadsheet(spreadsheetId);
        StringBuilder sb = new StringBuilder();
        sb.append(sp.getContent());

        List contents = new ArrayList();

        String lineitems[] = sb.toString().split("\n");
        for (int i = 0; i < lineitems.length; i++) {
            if (logger.isDebugEnabled())
                logger.debug("line item contents \n" + lineitems[i]);
            contents.add(lineitems[i]);
        }

        if (logger.isDebugEnabled())
            logger.debug(sp.toString());

        spreadsheet = new Spreadsheet();
        spreadsheet.setTitle(sp.getName());
        spreadsheet.setDate(sp.getDateCreated());
        spreadsheet.setUserId(sp.getCreator());
        spreadsheet.setLineitems(contents);

        assignmentList = new ArrayList();
        studentRows = new ArrayList();
        assignmentColumnSelectItems = new ArrayList();
        //
        // assignmentHeaders = new ArrayList();

        SpreadsheetHeader header = new SpreadsheetHeader((String) spreadsheet.getLineitems().get(0));
        assignmentHeaders = header.getHeaderWithoutUser();

        //generate spreadsheet rows
        Iterator it = spreadsheet.getLineitems().iterator();
        int rowcount = 0;
        int unknownusers = 0;
        while (it.hasNext()) {
            String line = (String) it.next();
            if (rowcount > 0) {
                SpreadsheetRow row = new SpreadsheetRow(line);
                studentRows.add(row);
                //check the number of unkonw users in spreadsheet
                if (!row.isKnown())
                    unknownusers = unknownusers + 1;
                if (logger.isDebugEnabled())
                    logger.debug("row added" + rowcount);
            }
            rowcount++;
        }
        rowCount = String.valueOf(rowcount - 1);
        if (unknownusers > 0) {
            this.hasUnknownUser = true;
        }

        //create a numeric list of assignment headers

        if (logger.isDebugEnabled())
            logger.debug("creating assignment List ---------");
        for (int i = 0; i < assignmentHeaders.size(); i++) {
            assignmentList.add(new Integer(i));
            if (logger.isDebugEnabled())
                logger.debug("col added" + i);
        }
        columnCount = String.valueOf(assignmentHeaders.size());

        for (int i = 0; i < assignmentHeaders.size(); i++) {
            SelectItem item = new SelectItem(new Integer(i + 1), (String) assignmentHeaders.get(i));
            if (logger.isDebugEnabled())
                logger.debug("creating selectItems " + item.getValue());
            assignmentColumnSelectItems.add(item);
        }

        if (logger.isDebugEnabled())
            logger.debug("Map initialized " + studentRows.size());
        if (logger.isDebugEnabled())
            logger.debug("assignmentList " + assignmentList.size());

        return "spreadsheetPreview";
    }

    public boolean isSelectedCategoryDropsScores() {
        return selectedCategoryDropsScores;
    }

    public void setSelectedCategoryDropsScores(boolean selectedCategoryDropsScores) {
        this.selectedCategoryDropsScores = selectedCategoryDropsScores;
    }

    public Category getAssignmentCategory() {
        return assignmentCategory;
    }

    public void setAssignmentCategory(Category assignmentCategory) {
        this.assignmentCategory = assignmentCategory;
    }

    public String processCategoryChangeInImport(ValueChangeEvent vce) {
        String changeCategory = (String) vce.getNewValue();
        selectedCategory = changeCategory;
        extraCreditCatSelected = extraCreditCategories.contains(selectedCategory);
        if (vce.getOldValue() != null && vce.getNewValue() != null
                && !vce.getOldValue().equals(vce.getNewValue())) {
            if (changeCategory.equals(UNASSIGNED_CATEGORY)) {
                selectedCategoryDropsScores = false;
                assignmentCategory = null;
                selectedCategory = getLocalizedString("cat_unassigned");
            } else {
                List<Category> categories = getGradebookManager().getCategories(getGradebookId());
                if (categories != null && categories.size() > 0) {
                    for (Category category : categories) {
                        if (changeCategory.equals(category.getId().toString())) {
                            selectedCategoryDropsScores = category.isDropScores();
                            category.setAssignmentList(retrieveCategoryAssignmentList(category));
                            assignmentCategory = category;
                            assignment.setPointsPossible(assignmentCategory.getItemValue());
                            selectedCategory = category.getId().toString();
                            break;
                        }
                    }
                }
            }
        }
        return "spreadsheetImport";
    }

    /**
     * Bulk import of grades from a freshly imported spreadsheet
     *
     * @return String for navigation
     *
     * @throws Exception
     */
    public String processFileEntire() throws Exception {
        InputStream inputStream = null;
        String fileName = null;
        List contents = null;

        int maxFileSizeInMB;
        try {
            maxFileSizeInMB = ServerConfigurationService.getInt(PROPERTY_FILE_SIZE_MAX, FILE_SIZE_DEFAULT);
        } catch (NumberFormatException nfe) {
            if (logger.isDebugEnabled())
                logger.debug("Invalid property set for gradebook max file size");
            maxFileSizeInMB = FILE_SIZE_DEFAULT;
        }
        long maxFileSizeInBytes = 1024L * 1024L * maxFileSizeInMB;

        boolean isXlsImport = false;
        boolean isOOXMLimport = false;

        if (upFile != null) {
            if (upFile != null && logger.isDebugEnabled()) {
                logger.debug("file size " + upFile.getSize() + "file name " + upFile.getName()
                        + "file Content Type " + upFile.getContentType() + "");
            }

            if (logger.isDebugEnabled())
                logger.debug("check that the file type is allowed");

            if (upFile.getName().endsWith("csv")) {
                isXlsImport = false;
            } else if (upFile.getName().endsWith("xls")) {
                isXlsImport = true;
            } else if (upFile.getName().endsWith("xlsx")) {
                isOOXMLimport = true;
            } else {
                FacesUtil.addErrorMessage(
                        getLocalizedString("import_entire_filetype_error", new String[] { upFile.getName() }));
                return null;
            }

            if (upFile.getSize() > maxFileSizeInBytes) {
                FacesUtil.addErrorMessage(
                        getLocalizedString("upload_view_filesize_error", new String[] { maxFileSizeInMB + "" }));
                return null;
            }

            fileName = upFile.getName();
            inputStream = new BufferedInputStream(upFile.getInputStream());
        } else {
            savePickedUploadFile();

            if (pickedFileReference != null) {
                if (logger.isDebugEnabled())
                    logger.debug("check that the file is csv file");

                if (pickedFileDesc == null) {
                    FacesUtil.addErrorMessage(
                            getLocalizedString("import_entire_filetype_error", new String[] { pickedFileDesc }));
                    return null;
                }

                if (logger.isDebugEnabled())
                    logger.debug("check that the file type is allowed");

                if (pickedFileDesc.endsWith("csv")) {
                    isXlsImport = false;
                } else if (pickedFileDesc.endsWith("xls")) {
                    isXlsImport = true;
                } else if (pickedFileDesc.endsWith("xlsx")) {
                    isOOXMLimport = true;
                } else {
                    FacesUtil.addErrorMessage(
                            getLocalizedString("import_entire_filetype_error", new String[] { pickedFileDesc }));
                    return null;
                }

                fileName = pickedFileDesc;

                ContentResource resource = getPickedContentResource();
                if (resource != null) {
                    // double check the file size does not exceed our limit
                    if (resource.getContentLength() > maxFileSizeInBytes) {
                        FacesUtil.addErrorMessage(getLocalizedString("upload_view_filesize_error",
                                new String[] { maxFileSizeInMB + "" }));
                        return null;
                    }
                }
                inputStream = getPickedFileStream(resource);

                clearPickedFile();
            } else {
                // all null - no uploaded or picked file
                if (logger.isDebugEnabled())
                    logger.debug("uploaded file not initialized");
                FacesUtil.addErrorMessage(getLocalizedString("import_entire_file_missing"));
                return null;
            }
        }

        if (inputStream == null) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_config_error"));
            return null;
        }

        try {
            if (isXlsImport) {
                contents = excelToArray(inputStream);
            } else if (isOOXMLimport) {
                contents = excelOOXMLToArray(inputStream);
            } else {
                contents = csvtoArray(inputStream);
            }
        } catch (IOException ioe) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_config_error"));
            return null;
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }

        // double check that the number of rows in this spreadsheet is reasonable
        int numStudentsInSite = getNumStudentsInSite();
        if (contents.size() > (numStudentsInSite + MAX_NUM_ROWS_OVER_CLASS_SIZE)) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_filerows_error",
                    new String[] { contents.size() + "", numStudentsInSite + "" }));
            return null;
        }

        // reset error lists
        unknownUsers = new ArrayList();
        unknownAssignments = new ArrayList();

        spreadsheet = new Spreadsheet();
        spreadsheet.setDate(new Date());
        spreadsheet.setTitle(this.getTitle());
        spreadsheet.setFilename(fileName);
        spreadsheet.setLineitems(contents);

        assignmentList = new ArrayList();
        studentRows = new ArrayList();
        assignmentColumnSelectItems = new ArrayList();

        SpreadsheetHeader header;
        try {
            header = new SpreadsheetHeader((String) spreadsheet.getLineitems().get(0));
            assignmentHeaders = header.getHeaderWithoutUserAndCumulativeGrade();
        } catch (IndexOutOfBoundsException ioe) {
            if (logger.isDebugEnabled())
                logger.debug(ioe + " there is a problem with the uploaded spreadsheet");
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_filecontent_error"));
            return null;
        }

        // check for blank header titles - don't want assignments added w/ blank titles
        Iterator headerIter = assignmentHeaders.iterator();
        // skip the name col
        headerIter.next();
        while (headerIter.hasNext()) {
            String itemTitle = (String) headerIter.next();
            if (itemTitle == null || itemTitle.trim().length() == 0) {
                FacesUtil.addErrorMessage(getLocalizedString("import_assignment_entire_missing_title"));
                return null;
            }
        }

        //generate spreadsheet rows
        Iterator it = spreadsheet.getLineitems().iterator();
        int rowcount = 0;
        int unknownusers = 0;
        int headerCount = assignmentHeaders.size();
        while (it.hasNext()) {
            String line = (String) it.next();
            if (rowcount > 0) {
                SpreadsheetRow row = new SpreadsheetRow(line);

                List rowData = row.getRowcontent();

                // if Cumulative column was in spreadsheet, need to filter it out
                // here
                if (header.isHasCumulative())
                    rowData.remove(rowData.size() - 1);

                // if the number of cols in the student row is less than the # headers,
                // we need to append blank placeholders
                if (rowData.size() < headerCount) {
                    while (rowData.size() < (headerCount)) {
                        rowData.add("");
                    }
                }
                studentRows.add(row);
                //check the number of unknown users in spreadsheet
                if (!row.isKnown()) {
                    unknownusers = unknownusers + 1;
                    unknownUsers.add(row.getUserId());
                }
                if (logger.isDebugEnabled())
                    logger.debug("row added" + rowcount);
            }
            rowcount++;
        }
        rowCount = String.valueOf(rowcount - 1); // subtract header
        if (unknownusers > 0) {
            this.hasUnknownUser = true;
            return null;
        }

        //create a numeric list of assignment headers

        if (logger.isDebugEnabled())
            logger.debug("creating assignment List ---------");
        for (int i = 0; i < assignmentHeaders.size() - 1; i++) {
            assignmentList.add(new Integer(i));
            if (logger.isDebugEnabled())
                logger.debug("col added" + i);
        }
        columnCount = String.valueOf(assignmentHeaders.size());

        for (int i = 0; i < assignmentHeaders.size(); i++) {
            SelectItem item = new SelectItem(new Integer(i + 1), (String) assignmentHeaders.get(i));
            if (logger.isDebugEnabled())
                logger.debug("creating selectItems " + item.getValue());
            assignmentColumnSelectItems.add(item);
        }

        if (logger.isDebugEnabled())
            logger.debug("Map initialized " + studentRows.size());
        if (logger.isDebugEnabled())
            logger.debug("assignmentList " + assignmentList.size());

        if (studentRows.size() < 1) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_filecontent_error"));
            return null;
        }

        return "spreadsheetVerify";
    }

    public String processFile() throws Exception {
        InputStream inputStream = null;
        String fileName = null;
        List contents = null;

        int maxFileSizeInMB;
        try {
            maxFileSizeInMB = ServerConfigurationService.getInt(PROPERTY_FILE_SIZE_MAX, FILE_SIZE_DEFAULT);
        } catch (NumberFormatException nfe) {
            if (logger.isDebugEnabled())
                logger.debug("Invalid property set for gradebook max file size");
            maxFileSizeInMB = FILE_SIZE_DEFAULT;
        }
        long maxFileSizeInBytes = 1024L * 1024L * maxFileSizeInMB;
        boolean isXlsImport = false;
        boolean isOOXMLimport = false;

        if (upFile != null) {
            if (upFile != null && logger.isDebugEnabled()) {
                logger.debug("file size " + upFile.getSize() + "file name " + upFile.getName()
                        + "file Content Type " + upFile.getContentType() + "");
            }

            if (logger.isDebugEnabled())
                logger.debug("check that the file type is allowed");

            if (upFile.getName().endsWith("csv")) {
                isXlsImport = false;
            } else if (upFile.getName().endsWith("xls")) {
                isXlsImport = true;
            } else if (upFile.getName().endsWith("xlsx")) {
                isOOXMLimport = true;
            } else {
                FacesUtil.addErrorMessage(
                        getLocalizedString("upload_view_filetype_error", new String[] { upFile.getName() }));
                return null;
            }

            if (upFile.getSize() > maxFileSizeInBytes) {
                FacesUtil.addErrorMessage(
                        getLocalizedString("upload_view_filesize_error", new String[] { maxFileSizeInMB + "" }));
                return null;
            }

            fileName = upFile.getName();
            inputStream = new BufferedInputStream(upFile.getInputStream());
        } else {
            savePickedUploadFile();

            if (pickedFileReference != null) {
                if (logger.isDebugEnabled())
                    logger.debug("check that the file is csv file");

                if (pickedFileDesc == null) {
                    FacesUtil.addErrorMessage(
                            getLocalizedString("upload_view_filetype_error", new String[] { pickedFileDesc }));
                    return null;
                }

                if (logger.isDebugEnabled())
                    logger.debug("check that the file type is allowed");

                if (pickedFileDesc.endsWith("csv")) {
                    isXlsImport = false;
                } else if (pickedFileDesc.endsWith("xls")) {
                    isXlsImport = true;
                } else if (pickedFileDesc.endsWith("xlsx")) {
                    isOOXMLimport = true;
                } else {
                    FacesUtil.addErrorMessage(
                            getLocalizedString("import_entire_filetype_error", new String[] { pickedFileDesc }));
                    return null;
                }

                fileName = pickedFileDesc;

                ContentResource resource = getPickedContentResource();
                if (resource != null) {
                    // double check the file size does not exceed our limit
                    if (resource.getContentLength() > maxFileSizeInBytes) {
                        FacesUtil.addErrorMessage(getLocalizedString("upload_view_filesize_error",
                                new String[] { maxFileSizeInMB + "" }));
                        return null;
                    }
                }
                inputStream = getPickedFileStream(resource);

                clearPickedFile();
            } else {
                // all null - no uploaded or picked file
                if (logger.isDebugEnabled())
                    logger.debug("uploaded file not initialized");
                FacesUtil.addErrorMessage(getLocalizedString("upload_view_failure"));
                return null;
            }
        }

        if (inputStream == null) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_config_error"));
            return null;
        }

        try {
            if (isXlsImport) {
                contents = excelToArray(inputStream);
            } else if (isOOXMLimport) {
                contents = excelOOXMLToArray(inputStream);
            } else {
                contents = csvtoArray(inputStream);
            }
        } catch (IOException ioe) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_config_error"));
            return null;
        }
        //SAK-23610 POI doesn't support Excel 5 
        catch (OldExcelFormatException oex) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_oldformat_error"));
            return null;
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }

        // double check that the number of rows in this spreadsheet is reasonable
        int numStudentsInSite = getNumStudentsInSite();
        if (contents.size() > (numStudentsInSite + MAX_NUM_ROWS_OVER_CLASS_SIZE)) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_filerows_error",
                    new String[] { contents.size() + "", numStudentsInSite + "" }));
            return null;
        }

        spreadsheet = new Spreadsheet();
        spreadsheet.setDate(new Date());
        // SAK-14173 - get title from session if available
        // and then clear the value from the session
        spreadsheet.setTitle(this.getTitle());
        clearImportTitle();
        spreadsheet.setFilename(fileName);
        spreadsheet.setLineitems(contents);
        assignmentList = new ArrayList();
        studentRows = new ArrayList();
        assignmentColumnSelectItems = new ArrayList();
        //
        // assignmentHeaders = new ArrayList();

        SpreadsheetHeader header;
        try {
            header = new SpreadsheetHeader((String) spreadsheet.getLineitems().get(0));
            assignmentHeaders = header.getHeaderWithoutUser();
        } catch (IndexOutOfBoundsException ioe) {
            if (logger.isDebugEnabled())
                logger.debug(ioe + " there is a problem with the uploaded spreadsheet");
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_filecontent_error"));
            return null;
        }

        //generate spreadsheet rows
        Iterator it = spreadsheet.getLineitems().iterator();
        int rowcount = 0;
        int unknownusers = 0;
        while (it.hasNext()) {
            String line = (String) it.next();
            if (rowcount > 0) {
                SpreadsheetRow row = new SpreadsheetRow(line);
                studentRows.add(row);
                //check the number of unkonw users in spreadsheet
                if (!row.isKnown())
                    unknownusers = unknownusers + 1;
                if (logger.isDebugEnabled())
                    logger.debug("row added" + rowcount);
            }
            rowcount++;
        }
        rowCount = String.valueOf(rowcount - 1);
        if (unknownusers > 0) {
            this.hasUnknownUser = true;
        }

        //create a numeric list of assignment headers

        if (logger.isDebugEnabled())
            logger.debug("creating assignment List ---------");
        for (int i = 0; i < assignmentHeaders.size(); i++) {
            assignmentList.add(new Integer(i));
            if (logger.isDebugEnabled())
                logger.debug("col added" + i);
        }
        columnCount = String.valueOf(assignmentHeaders.size());

        for (int i = 0; i < assignmentHeaders.size(); i++) {
            SelectItem item = new SelectItem(new Integer(i + 1), (String) assignmentHeaders.get(i));
            if (logger.isDebugEnabled())
                logger.debug("creating selectItems " + item.getValue());
            assignmentColumnSelectItems.add(item);
        }

        if (logger.isDebugEnabled())
            logger.debug("Map initialized " + studentRows.size());
        if (logger.isDebugEnabled())
            logger.debug("assignmentList " + assignmentList.size());

        if (studentRows.size() < 1) {
            FacesUtil.addErrorMessage(getLocalizedString("upload_view_filecontent_error"));
            return null;
        }

        return "spreadsheetUploadPreview";
    }

    /**
     * method converts an input stream to an List consist of strings
     * representing a line
     *
     * @param inputStream
     * @return contents
     */
    private List csvtoArray(InputStream inputStream) throws IOException {

        /**
         * TODO this well probably be removed
         */

        if (logger.isDebugEnabled())
            logger.debug("csvtoArray()");
        List contents = new ArrayList();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ((line = reader.readLine()) != null) {
            //logger.debug("contents of line: "+line);
            if (line.replaceAll(",", "").replaceAll("\"", "").equals("")) {
                continue;
            }

            contents.add(line);
        }
        return contents;

    }

    /**
     * method to save CSV to database
     *
     * @return String
     */
    public String saveFile() {

        StringBuilder sb = new StringBuilder();
        List contents = spreadsheet.getLineitems();
        Iterator it = contents.iterator();
        while (it.hasNext()) {
            String line = (String) it.next();
            sb.append(line + '\n');
        }

        String filename = spreadsheet.getFilename();

        /** temporary presistence code
         *
         */
        if (logger.isDebugEnabled())
            logger.debug("string to save " + sb.toString());
        try {
            getGradebookManager().createSpreadsheet(getGradebookId(), spreadsheet.getTitle(),
                    this.getUserDirectoryService().getUserDisplayName(getUserUid()), new Date(), sb.toString());
        } catch (ConflictingSpreadsheetNameException e) {
            if (logger.isDebugEnabled())
                logger.debug(e);
            FacesUtil.addErrorMessage(getLocalizedString("upload_preview_save_failure"));
            return null;
        }
        FacesUtil.addRedirectSafeMessage(
                getLocalizedString("upload_preview_save_confirmation", new String[] { filename }));

        this.setPageName("spreadsheetListing");
        return "spreadsheetListing";
    }

    /**
     * If user has selected column to import, grab the values and
     */
    public String importData() {

        FacesContext facesContext = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();

        if (logger.isDebugEnabled())
            logger.debug("processFile()");
        String selectedColumn = request.getParameter("form:assignment");
        if (logger.isDebugEnabled())
            logger.debug("the selected column is " + selectedColumn);

        selectedAssignment = new HashMap();
        try {
            selectedAssignment.put("Assignment", assignmentHeaders.get(Integer.parseInt(selectedColumn) - 1));
        } catch (Exception e) {
            if (logger.isDebugEnabled())
                logger.debug("no assignment selected");
            FacesUtil.addErrorMessage(getLocalizedString("import_preview_assignment_selection_failure"));
            return null;
        }

        Iterator it = studentRows.iterator();
        if (logger.isDebugEnabled())
            logger.debug("number of student rows " + studentRows.size());
        int i = 0;
        while (it.hasNext()) {

            if (logger.isDebugEnabled())
                logger.debug("row " + i);
            SpreadsheetRow row = (SpreadsheetRow) it.next();
            List line = row.getRowcontent();

            String userid = "";
            String user = (String) line.get(0);
            try {
                userid = ((User) rosterMap.get(line.get(0))).getUserUid();
            } catch (Exception e) {
                if (logger.isDebugEnabled())
                    logger.debug("user " + user + "is not known to the system");
                userid = "";
            }

            String points;
            try {
                int index = Integer.parseInt(selectedColumn);
                if (line.size() > index) {
                    points = (String) line.get(index);
                } else {
                    logger.info("unable to find any points for " + userid + " in spreadsheet");
                    points = "";
                }
            } catch (NumberFormatException e) {
                if (logger.isDebugEnabled())
                    logger.debug(e);
                points = "";
            }
            if (logger.isDebugEnabled())
                logger.debug("user " + user + " userid " + userid + " points " + points);
            if (!"".equals(points) && (!"".equals(userid))) {
                selectedAssignment.put(userid, points);
            }
            i++;
        }
        if (logger.isDebugEnabled())
            logger.debug("scores to import " + i);

        spreadsheet.setSelectedAssignment(selectedAssignment);

        if (assignment == null) {
            assignment = new Assignment();
            assignment.setReleased(true);
        }

        try {
            scores = spreadsheet.getSelectedAssignment();
            assignment.setName((String) scores.get("Assignment"));
        } catch (NullPointerException npe) {
            if (logger.isDebugEnabled())
                logger.debug("scores not set");
        }

        return "spreadsheetImport";
    }

    /**
     * Takes the spreadsheet data imported and updates/adds to what is in the database
     */
    public String importDataAndSaveAll() {
        boolean gbUpdated = false;
        hasUnknownAssignments = false;
        externallyMaintainedImportMsg = new StringBuilder();

        LetterGradePercentMapping lgpm = new LetterGradePercentMapping();
        if (getGradeEntryByLetter()) {
            lgpm = getGradebookManager().getLetterGradePercentMapping(localGradebook);
        }

        if (logger.isDebugEnabled())
            logger.debug("importDataAll()");

        // first, verify imported data is valid
        if (!verifyImportedData(lgpm))
            return "spreadsheetVerify";

        List grAssignments = getGradebookManager().getAssignments(getGradebook().getId());
        Iterator assignIter = assignmentHeaders.iterator();

        // since the first two columns are user ids and name, skip over
        int index = 1;
        if (assignIter.hasNext())
            assignIter.next();

        while (assignIter.hasNext()) {
            String assignmentName = (String) assignIter.next();
            String pointsPossibleAsString = null;

            String[] parsedAssignmentName = assignmentName.split(" \\[");

            assignmentName = parsedAssignmentName[0].trim();
            Double pointsPossible = null;
            if (parsedAssignmentName.length > 1) {
                String[] parsedPointsPossible = parsedAssignmentName[1].split("\\]");
                if (parsedPointsPossible.length > 0) {
                    pointsPossibleAsString = parsedPointsPossible[0].trim();
                    try {
                        pointsPossible = convertStringToDouble(pointsPossibleAsString);
                        pointsPossible = new Double(FacesUtil.getRoundDown(pointsPossible.doubleValue(), 2));
                        if (pointsPossible <= 0)
                            pointsPossibleAsString = null;
                    } catch (ParseException e) {
                        pointsPossibleAsString = null;
                    }
                }
            }

            // probably last column but not sure, so continue
            if (getLocalizedString(CUMULATIVE_GRADE_STRING).equals(assignmentName)) {
                continue;
            }

            index++;

            // Get Assignment object from assignment name
            Assignment assignment = getAssignmentByName(grAssignments, assignmentName);
            List gradeRecords = new ArrayList();

            // if assignment == null, need to create a new one plus all the grade records
            // if exists, need find those that are changed and only apply those
            if (assignment == null) {

                if (pointsPossible != null) {
                    // params: gradebook id, name of assignment, points possible, due date, NOT counted, is released
                    assignmentId = getGradebookManager().createAssignment(getGradebookId(), assignmentName,
                            pointsPossible, null, Boolean.FALSE, Boolean.TRUE, Boolean.FALSE);
                    assignment = getGradebookManager().getAssignment(assignmentId);
                } else {
                    // for this version, display error message saying non-match between import
                    // and current gradebook assignments
                    hasUnknownAssignments = true;
                    unknownAssignments.add(assignmentName);

                    continue;
                }

                Iterator it = studentRows.iterator();

                if (logger.isDebugEnabled())
                    logger.debug("number of student rows " + studentRows.size());
                int i = 1;

                while (it.hasNext()) {
                    if (logger.isDebugEnabled())
                        logger.debug("row " + i);
                    SpreadsheetRow row = (SpreadsheetRow) it.next();
                    List line = row.getRowcontent();

                    String userid = "";
                    String user = (String) line.get(0);
                    try {
                        userid = ((User) rosterMap.get(user)).getUserUid();
                    } catch (Exception e) {
                        if (logger.isDebugEnabled())
                            logger.debug("user " + user + "is not known to the system");
                        userid = "";
                        // checked when imported from user's system so should not happen at this point.
                    }

                    if (line.size() > index) {
                        String inputScore = (String) line.get(index);

                        if (inputScore != null && inputScore.trim().length() > 0) {
                            Double scoreAsDouble = null;
                            String scoreAsString = inputScore.trim();

                            AssignmentGradeRecord asnGradeRecord = new AssignmentGradeRecord(assignment, userid,
                                    null);

                            // truncate input points/% to 2 decimal places
                            if (getGradeEntryByPoints() || getGradeEntryByPercent()) {
                                try {
                                    scoreAsDouble = convertStringToDouble(scoreAsString);
                                    scoreAsDouble = new Double(
                                            FacesUtil.getRoundDown(scoreAsDouble.doubleValue(), 2));
                                    asnGradeRecord.setPercentEarned(scoreAsDouble);
                                    asnGradeRecord.setPointsEarned(scoreAsDouble);
                                    gradeRecords.add(asnGradeRecord);
                                    if (logger.isDebugEnabled())
                                        logger.debug("user " + user + " userid " + userid + " score "
                                                + inputScore.toString());
                                } catch (ParseException pe) {
                                    // this should have been caught during validation, so there is a problem
                                    logger.error("ParseException encountered parsing " + scoreAsString);
                                }
                            } else if (getGradeEntryByLetter()) {
                                scoreAsString = (String) inputScore;

                                asnGradeRecord.setLetterEarned(scoreAsString.trim());
                                gradeRecords.add(asnGradeRecord);
                                if (logger.isDebugEnabled())
                                    logger.debug("user " + user + " userid " + userid + " score "
                                            + inputScore.toString());
                            }
                        }
                    }

                    i++;
                }

                gbUpdated = true;
            } else {
                if (!assignment.getPointsPossible().equals(pointsPossible)) {
                    if (assignment.isExternallyMaintained()) {
                        externallyMaintainedImportMsg
                                .append(getLocalizedString("import_assignment_externally_maintained_settings",
                                        new String[] { Validator.escapeHtml(assignment.getName()),
                                                Validator.escapeHtml(assignment.getExternalAppName()) })
                                        + "<br />");
                    } else if (pointsPossible != null) {
                        assignment.setPointsPossible(pointsPossible);
                        getGradebookManager().updateAssignment(assignment);
                        gbUpdated = true;
                    }
                }

                gradeRecords = gradeChanges(assignment, studentRows, index + 1, lgpm);

                if (gradeRecords.size() == 0)
                    continue; // no changes to current grade record so go to next one
                else {
                    gbUpdated = true;
                }
            }

            getGradebookManager().updateAssignmentGradeRecords(assignment, gradeRecords,
                    getGradebook().getGrade_type());
            getGradebookBean().getEventTrackingService().postEvent("gradebook.importEntire",
                    "/gradebook/" + getGradebookId() + "/" + assignment.getName() + "/" + getAuthzLevel());
        }

        // just in case previous attempt had unknown users
        hasUnknownUser = false;
        if (gbUpdated) {
            if (!hasUnknownAssignments) {
                FacesUtil.addRedirectSafeMessage(getLocalizedString(IMPORT_SUCCESS_STRING));
            } else {
                FacesUtil.addRedirectSafeMessage(getLocalizedString(IMPORT_SOME_SUCCESS_STRING));
            }
        } else if (!hasUnknownAssignments) {
            FacesUtil.addRedirectSafeMessage(getLocalizedString(IMPORT_NO_CHANGES));
        }

        this.setPageName("spreadsheetAll");
        return "spreadsheetAll";
    }

    /**
     * Returns TRUE if specific value imported from spreadsheet is valid
     *
     * @return false if the spreadsheet contains a invalid points possible, an invalid
     * score value, more than one column for the same gb item, more than one row for the same student
     */
    private boolean verifyImportedData(LetterGradePercentMapping lgpm) {
        if (studentRows == null || studentRows.isEmpty()) {
            return true;
        }

        if (getGradeEntryByLetter() && (lgpm == null || lgpm.getGradeMap() == null)) {
            FacesUtil.addErrorMessage(getLocalizedString("gb_setup_no_grade_entry_scale"));
            return false;
        }

        // determine the index of the "cumulative" column
        int indexOfCumColumn = -1;
        if (assignmentHeaders != null && !assignmentHeaders.isEmpty()) {
            // add one b/c assignmentHeaders does not include the username col but studentRows does
            indexOfCumColumn = assignmentHeaders.indexOf(getLocalizedString(CUMULATIVE_GRADE_STRING)) + 1;

            // we need to double check that there aren't any duplicate assignments
            // in the spreadsheet. the first column is the student name, so skip
            List<String> assignmentNames = new ArrayList<String>();
            if (assignmentHeaders.size() > 1) {
                for (int i = 1; i < assignmentHeaders.size(); i++) {
                    if (i == indexOfCumColumn) {
                        continue;
                    }

                    String header = (String) assignmentHeaders.get(i);
                    String[] parsedAssignmentName = header.split(" \\[");
                    String assignmentName = parsedAssignmentName[0].trim();
                    if (assignmentNames.contains(assignmentName)) {
                        FacesUtil.addErrorMessage(getLocalizedString("import_assignment_duplicate_titles",
                                new String[] { assignmentName }));
                        return false;
                    }

                    assignmentNames.add(assignmentName);
                }
            }
        }

        List<String> uploadedStudents = new ArrayList<String>();

        for (int row = 0; row < studentRows.size(); row++) {
            SpreadsheetRow scoreRow = (SpreadsheetRow) studentRows.get(row);
            List studentScores = scoreRow.getRowcontent();

            // verify that a student doesn't appear more than once in the ss
            if (studentScores != null) {
                String username = (String) studentScores.get(0);
                if (username != null) {
                    if (uploadedStudents.contains(username)) {
                        FacesUtil.addErrorMessage(getLocalizedString("import_assignment_duplicate_student",
                                new String[] { username }));
                        return false;
                    }

                    uploadedStudents.add(username);
                }
            }

            // start with col 2 b/c the first two are eid and name
            if (studentScores != null && studentScores.size() > 2) {
                for (int i = 2; i < studentScores.size(); i++) {
                    if (i == indexOfCumColumn)
                        continue;

                    String scoreAsString = ((String) studentScores.get(i)).trim();
                    if (scoreAsString != null && scoreAsString.length() > 0) {

                        if (getGradeEntryByPoints() || getGradeEntryByPercent()) {
                            Double scoreAsDouble;

                            try {
                                if (logger.isDebugEnabled())
                                    logger.debug("checking if " + scoreAsString + " is a numeric value");

                                scoreAsDouble = convertStringToDouble(scoreAsString);
                                // check for negative values
                                if (scoreAsDouble.doubleValue() < 0) {
                                    if (logger.isDebugEnabled())
                                        logger.debug(scoreAsString + " is not a positive value");
                                    FacesUtil.addErrorMessage(getLocalizedString(IMPORT_ASSIGNMENT_NEG_VALUE));

                                    return false;
                                }
                            } catch (ParseException e) {
                                if (logger.isDebugEnabled())
                                    logger.debug(scoreAsString + " is not a numeric value");
                                FacesUtil.addErrorMessage(getLocalizedString(IMPORT_ASSIGNMENT_NOTSUPPORTED));

                                return false;
                            }

                        } else if (getGradeEntryByLetter()) {
                            String standardizedLetterGrade = lgpm.standardizeInputGrade(scoreAsString);
                            if (standardizedLetterGrade == null) {
                                FacesUtil.addErrorMessage(getLocalizedString("import_entire_invalid_letter"));
                                return false;
                            }
                        }
                    }
                }
            }
        }

        return true;
    }

    /**
     * Returns a list of AssignmentGradeRecords that are different than in current
     * Gradebook. Returns empty List if no differences found.
     *
     * @param assignment
     *          The Assignment object whose grades need to be checked
     * @param fromSpreadsheet
     *          The rows of grades from the imported spreadsheet
     * @param index
     *          The column of spreadsheet to check
     *
     * @return
     *          List containing AssignmentGradeRecords for those student's grades that
     *          have changed
     */
    private List gradeChanges(Assignment assignment, List fromSpreadsheet, int index,
            LetterGradePercentMapping lgpm) {
        List updatedGradeRecords = new ArrayList();
        List studentUids = new ArrayList();
        List studentRowsWithUids = new ArrayList();

        Iterator it = fromSpreadsheet.iterator();

        while (it.hasNext()) {
            final SpreadsheetRow row = (SpreadsheetRow) it.next();
            List line = row.getRowcontent();

            String userid = "";
            final String user = ((String) line.get(0)).toLowerCase();
            try {
                userid = ((User) rosterMap.get(user)).getUserUid();

                // create list of uids to get current grades from gradebook
                studentUids.add(userid);

                // add uid to each row so can check spreadsheet value against currently stored
                List linePlus = new ArrayList();
                linePlus.add(userid);
                linePlus.addAll(line);
                studentRowsWithUids.add(linePlus);

            } catch (Exception e) {
                // Weirdness. Should be caught when importing, not here
            }
        }

        List gbGrades = getGradebookManager().getAssignmentGradeRecordsConverted(assignment, studentUids);

        // now do the actual comparison
        it = studentRowsWithUids.iterator();

        boolean updatingExternalGrade = false;
        while (it.hasNext()) {
            final List aRow = (List) it.next();

            final String userid = (String) aRow.get(0);
            final String user = (String) aRow.get(1);

            AssignmentGradeRecord gr = findGradeRecord(gbGrades, userid);

            String score = null;
            if (index < aRow.size()) {
                score = ((String) aRow.get(index)).trim();
            }

            if (getGradeEntryByPercent() || getGradeEntryByPoints()) {
                Double scoreEarned = null;
                boolean updateScore = true;
                if (score != null && !"".equals(score)) {
                    try {
                        scoreEarned = convertStringToDouble(score);
                    } catch (ParseException pe) {
                        // this should have already been validated at this point, so there is
                        // something wrong if we made it here
                        logger.error(
                                "ParseException encountered while checking for grade updates with score: " + score);
                        updateScore = false;
                    }

                    // truncate to 2 decimal places
                    if (scoreEarned != null)
                        scoreEarned = new Double(FacesUtil.getRoundDown(scoreEarned.doubleValue(), 2));
                }

                if (updateScore) {
                    if (gr == null) {
                        if (scoreEarned != null) {
                            if (!assignment.isExternallyMaintained()) {
                                gr = new AssignmentGradeRecord(assignment, userid, scoreEarned);
                                gr.setPercentEarned(scoreEarned); // manager will handle if % vs point grading
                                updatedGradeRecords.add(gr);
                            } else {
                                updatingExternalGrade = true;
                            }
                        }
                    } else {
                        // we need to truncate points earned to 2 decimal places to more accurately
                        // see if it was changed - scores that are entered as % can be stored with
                        // unlimited decimal places in db
                        Double gbScoreEarned = null;
                        if (getGradeEntryByPercent())
                            gbScoreEarned = gr.getPercentEarned();
                        else
                            gbScoreEarned = gr.getPointsEarned();

                        if (gbScoreEarned != null)
                            gbScoreEarned = new Double(FacesUtil.getRoundDown(gbScoreEarned.doubleValue(), 2));

                        // 3 ways points earned different: 1 null other not (both ways) or actual
                        // values different
                        if ((gbScoreEarned == null && scoreEarned != null)
                                || (gbScoreEarned != null && scoreEarned == null)
                                || (gbScoreEarned != null && scoreEarned != null
                                        && gbScoreEarned.doubleValue() != scoreEarned.doubleValue())) {

                            gr.setPointsEarned(scoreEarned); //manager will use correct field depending on grade entry method
                            gr.setPercentEarned(scoreEarned);
                            if (!assignment.isExternallyMaintained())
                                updatedGradeRecords.add(gr);
                            else
                                updatingExternalGrade = true;
                        }
                    }
                }
            } else if (getGradeEntryByLetter()) {
                if (lgpm == null || lgpm.getGradeMap() == null)
                    return null;
                if (score != null && score.length() > 0) {
                    score = lgpm.standardizeInputGrade(score);
                }

                if (gr == null) {
                    if (score != null && score.length() > 0) {
                        if (!assignment.isExternallyMaintained()) {
                            gr = new AssignmentGradeRecord(assignment, userid, null);
                            gr.setLetterEarned(score);
                            updatedGradeRecords.add(gr);
                        } else {
                            updatingExternalGrade = true;
                        }
                    }
                } else {
                    String gbLetterEarned = gr.getLetterEarned();

                    if ((gbLetterEarned != null && !gbLetterEarned.equals(score))
                            || (gbLetterEarned == null && score != null)) {

                        gr.setLetterEarned(score);
                        if (!assignment.isExternallyMaintained())
                            updatedGradeRecords.add(gr);
                        else
                            updatingExternalGrade = true;
                    }
                }
            }
        }

        if (updatingExternalGrade)
            externallyMaintainedImportMsg
                    .append(getLocalizedString("import_assignment_externally_maintained_grades",
                            new String[] { Validator.escapeHtml(assignment.getName()),
                                    Validator.escapeHtml(assignment.getExternalAppName()) })
                            + "<br/>");

        return updatedGradeRecords;
    }

    /**
     * Finds the AssignmentGradeRecord for userid passed in (if it exists).
     *
     * @param gbGrades
     *          List of AssignmentGradeRecord objects.
     * @param userid
     *          String of user id to find.
     *
     * @return
     *          AssignmentGradeRecord if it's student id matches id passed in. NULL otherwise.
     */
    private AssignmentGradeRecord findGradeRecord(List gbGrades, String userid) {
        Iterator it = gbGrades.iterator();

        while (it.hasNext()) {
            AssignmentGradeRecord agr = (AssignmentGradeRecord) it.next();

            if (agr.getStudentId().equals(userid)) {
                it.remove(); // for efficiency
                return agr;
            }
        }

        return null;
    }

    /**
     * Used to find assignment in gradebook by its name
     *
     * @param list The list of gradebook assignments
     * @param name The String to look for
     *
     * @return Assignment object if found, null otherwise
     */
    private Assignment getAssignmentByName(List assignList, String name) {
        for (Iterator assignIter = assignList.iterator(); assignIter.hasNext();) {
            Assignment assignment = (Assignment) assignIter.next();

            if (assignment.getName().trim().equalsIgnoreCase(name.trim())) {
                // remove for performance
                assignIter.remove();
                return assignment;
            }
        }

        return null;
    }

    /**
     * Cancel import and return to Import Grades page.
     *
     * @return String to navigate to Import Grades page.
     */
    public String processImportAllCancel() {
        hasUnknownUser = false;
        hasUnknownAssignments = false;
        return "spreadsheetAll";
    }

    //save grades and comments
    public String saveGrades() {

        if (logger.isDebugEnabled())
            logger.debug("create assignment and save grades");
        if (logger.isDebugEnabled())
            logger.debug("first check if all variables are numeric");

        logger.debug("********************" + scores);

        LetterGradePercentMapping lgpm = new LetterGradePercentMapping();
        if (getGradeEntryByLetter()) {
            lgpm = getGradebookManager().getLetterGradePercentMapping(getGradebook());
        }

        Iterator iter = scores.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            if (!entry.getKey().equals("Assignment")) {
                if (getGradeEntryByPoints() || getGradeEntryByPercent()) {
                    String points = (String) entry.getValue();
                    try {
                        if (logger.isDebugEnabled())
                            logger.debug("checking if " + points + " is a numeric value");

                        double score = convertStringToDouble(points);

                        if (score < 0) {
                            FacesUtil.addErrorMessage(getLocalizedString("import_assignment_negative"));
                            return "spreadsheetPreview";
                        }

                    } catch (ParseException e) {
                        if (logger.isDebugEnabled())
                            logger.debug(points + " is not a numeric value");
                        FacesUtil.addErrorMessage(getLocalizedString("import_assignment_notsupported"));

                        return "spreadsheetPreview";
                    }
                } else if (getGradeEntryByLetter()) {
                    if (lgpm.getGradeMap() == null) {
                        FacesUtil.addErrorMessage(getLocalizedString("gb_setup_no_grade_entry_scale"));
                        return "spreadsheetPreview";
                    }
                    String letterScore = (String) entry.getValue();
                    if (letterScore != null && letterScore.length() > 0) {
                        String formattedLetterScore = lgpm.standardizeInputGrade(letterScore);
                        if (formattedLetterScore == null) {
                            FacesUtil.addErrorMessage(getLocalizedString("import_assignment_invalid_letter"));
                            return "spreadsheetPreview";
                        }
                    }
                }
            }
        }

        try {
            Category newCategory = retrieveSelectedCategory();
            if (newCategory != null) {
                assignmentId = getGradebookManager().createAssignmentForCategory(getGradebookId(),
                        newCategory.getId(), assignment.getName(), assignment.getPointsPossible(),
                        assignment.getDueDate(), new Boolean(assignment.isNotCounted()),
                        new Boolean(assignment.isReleased()), new Boolean(assignment.isExtraCredit()));
            } else {
                assignmentId = getGradebookManager().createAssignment(getGradebookId(), assignment.getName(),
                        assignment.getPointsPossible(), assignment.getDueDate(),
                        new Boolean(assignment.isNotCounted()), new Boolean(assignment.isReleased()),
                        new Boolean(assignment.isExtraCredit()));
            }

            FacesUtil.addRedirectSafeMessage(
                    getLocalizedString("add_assignment_save", new String[] { assignment.getName() }));

            assignment = getGradebookManager().getAssignment(assignmentId);
            List gradeRecords = new ArrayList();

            //initialize comment List
            List comments = new ArrayList();
            //check if a comments column is selected for the defalt select item value is
            // 0 which mean no comments to be imported
            if (selectedCommentsColumnId != null && selectedCommentsColumnId > 0)
                comments = createCommentList(assignment);

            if (logger.isDebugEnabled())
                logger.debug("remove title entry form map");
            scores.remove("Assignment");
            if (logger.isDebugEnabled())
                logger.debug("iterate through scores and and save assignment grades");

            Iterator it = scores.entrySet().iterator();
            while (it.hasNext()) {

                Map.Entry entry = (Map.Entry) it.next();
                String uid = (String) entry.getKey();
                String scoreAsString = (String) entry.getValue();
                if (scoreAsString != null && scoreAsString.trim().length() > 0) {
                    if (getGradeEntryByPercent() || getGradeEntryByPoints()) {
                        try {
                            Double scoreAsDouble;
                            scoreAsDouble = convertStringToDouble(scoreAsString);
                            if (scoreAsDouble != null)
                                scoreAsDouble = new Double(FacesUtil.getRoundDown(scoreAsDouble.doubleValue(), 2));
                            AssignmentGradeRecord asnGradeRecord = new AssignmentGradeRecord(assignment, uid,
                                    scoreAsDouble);
                            asnGradeRecord.setPercentEarned(scoreAsDouble); // in case gb entry by % - sorted out in manager
                            gradeRecords.add(asnGradeRecord);
                            if (logger.isDebugEnabled())
                                logger.debug("added grades for " + uid + " - score " + scoreAsString);
                        } catch (ParseException pe) {
                            // the score should have already been validated at this point, so
                            // there is something wrong
                            logger.error("ParseException encountered while parsing value: " + scoreAsString
                                    + " Score was not updated.");
                        }
                    } else if (getGradeEntryByLetter()) {
                        AssignmentGradeRecord asnGradeRecord = new AssignmentGradeRecord(assignment, uid, null);
                        asnGradeRecord.setLetterEarned(lgpm.standardizeInputGrade(scoreAsString));
                        gradeRecords.add(asnGradeRecord);
                    }
                }
            }

            if (logger.isDebugEnabled())
                logger.debug("persist grade records to database");
            getGradebookManager().updateAssignmentGradesAndComments(assignment, gradeRecords, comments);
            getGradebookBean().getEventTrackingService().postEvent("gradebook.importItem",
                    "/gradebook/" + getGradebookId() + "/" + assignment.getName() + "/" + getAuthzLevel());

            return "spreadsheetListing";

        } catch (ConflictingAssignmentNameException e) {
            if (logger.isErrorEnabled())
                logger.error(e);
            FacesUtil.addErrorMessage(getLocalizedString("add_assignment_name_conflict_failure"));
        }

        return null;
    }

    /**
     * method creates a collection of comment
     * objects from a the saved spreadsheet and
     * selected column. requires an assignment as parameter to set the
     * gradableObject property of the comment
     *
     * @param assignmentTobeCommented
     * @return  List of comment comment objects
     */
    public List createCommentList(Assignment assignmentTobeCommented) {

        List comments = new ArrayList();
        Iterator it = studentRows.iterator();
        while (it.hasNext()) {
            SpreadsheetRow row = (SpreadsheetRow) it.next();
            List line = row.getRowcontent();

            String userid = "";
            String user = (String) line.get(0);
            try {
                userid = ((User) rosterMap.get(line.get(0))).getUserUid();
                String commentText = (String) line.get(selectedCommentsColumnId.intValue());
                if ((!commentText.equals(""))) {
                    Comment comment = new Comment(userid, commentText, assignmentTobeCommented);
                    comments.add(comment);
                }
            } catch (Exception e) {
                if (logger.isDebugEnabled())
                    logger.debug("student is required  and " + user + "is not known to this gradebook");
            }
        }
        return comments;
    }

    public Integer getSelectedCommentsColumnId() {
        return selectedCommentsColumnId;
    }

    public void setSelectedCommentsColumnId(Integer selectedCommentsColumnId) {
        this.selectedCommentsColumnId = selectedCommentsColumnId;
    }

    /**
     *
     */

    public class Spreadsheet implements Serializable {

        private String title;
        private Date date;
        private String userId;
        private String contents;
        private String displayName;
        private Long gradebookId;
        private String filename;
        private List lineitems;
        private Map selectedAssignment;

        public Spreadsheet(String title, Date date, String userId, String contents) {

            if (logger.isDebugEnabled())
                logger.debug("loading Spreadsheet()");
            this.title = title;
            this.date = date;
            this.userId = userId;
            this.contents = contents;
        }

        public Spreadsheet() {
            if (logger.isDebugEnabled())
                logger.debug("loading Spreadsheet()");
        }

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            this.date = date;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getContents() {
            return contents;
        }

        public void setContents(String contents) {
            this.contents = contents;
        }

        public String getDisplayName() {
            return displayName;
        }

        public void setDisplayName(String displayName) {
            this.displayName = displayName;
        }

        public Long getGradebookId() {
            return gradebookId;
        }

        public void setGradebookId(Long gradebookId) {
            this.gradebookId = gradebookId;
        }

        public String getFilename() {
            return filename;
        }

        public void setFilename(String filename) {
            this.filename = filename;
        }

        public List getLineitems() {
            return lineitems;
        }

        public void setLineitems(List lineitems) {
            this.lineitems = lineitems;
        }

        public Map getSelectedAssignment() {
            //logger.debug(this.selectedAssignment);
            return selectedAssignment;
        }

        public void setSelectedAssignment(Map selectedAssignment) {
            this.selectedAssignment = selectedAssignment;
            //logger.debug(selectedAssignment);
        }

        public String toString() {
            return "Spreadsheet{" + "title='" + title + '\'' + ", date=" + date + ", userId='" + userId + '\''
                    + ", contents='" + contents + '\'' + ", displayName='" + displayName + '\'' + ", gradebookId="
                    + gradebookId + ", filename='" + filename + '\'' + ", lineitems=" + lineitems
                    + ", selectedAssignment=" + selectedAssignment + '}';
        }
    }

    /**
     * spreadsheet header class
     */

    public class SpreadsheetHeader implements Serializable {

        private List header;
        private int columnCount;
        private boolean hasCumulative;

        public List getHeader() {
            return header;
        }

        public void setHeader(List header) {
            this.header = header;
        }

        public int getColumnCount() {
            return columnCount;
        }

        public void setColumnCount(int columnCount) {
            this.columnCount = columnCount;
        }

        public boolean isHasCumulative() {
            return hasCumulative;
        }

        public void setHasCumulative(boolean hasCumulative) {
            this.hasCumulative = hasCumulative;
        }

        public List getHeaderWithoutUser() {
            List head = header;
            head.remove(0);
            return head;
        }

        public List getHeaderWithoutUserAndCumulativeGrade() {
            List head = getHeaderWithoutUser();
            // If CSV from Roster page, last column will be Cumulative Grade
            // so remove from header list
            if (head.get(head.size() - 1).equals("Cumulative")) {
                head.remove(head.size() - 1);
            }

            return head;
        }

        public SpreadsheetHeader(String source) {

            if (logger.isDebugEnabled())
                logger.debug("creating header from " + source);
            header = new ArrayList();
            CSV csv = new CSV();
            header = csv.parse(source);
            columnCount = header.size();
            hasCumulative = header.get(columnCount - 1).equals("Cumulative");
        }

    }

    /**
     * spreadsheetRow class
     */
    public class SpreadsheetRow implements Serializable {

        private List rowcontent;
        private int columnCount;
        private String userDisplayName;
        private String userId;
        private String userUid;
        private boolean isKnown;

        public SpreadsheetRow(String source) {

            // this may be instantiated before SpreadsheetUploadBean is initialized, so make sure
            // the rosterMap is populated
            if (rosterMap == null) {
                initializeRosterMap();
            }

            if (logger.isDebugEnabled())
                logger.debug("creating row from string " + source);
            rowcontent = new ArrayList();
            CSV csv = new CSV();
            rowcontent = csv.parse(source);

            // derive the user information
            String userContent = (String) rowcontent.get(0);
            if (userContent != null) {
                userId = userContent.toLowerCase();

                // check to see if this student is in the roster
                if (rosterMap.containsKey(userId)) {
                    isKnown = true;
                    User user = (User) rosterMap.get(userId);
                    userDisplayName = user.getDisplayName();
                    userUid = user.getUserUid();

                    if (logger.isDebugEnabled())
                        logger.debug("get userid " + userId + "username is " + userDisplayName);
                } else {
                    isKnown = false;
                    userDisplayName = getLocalizedString("import_preview_unknown_name");
                    userUid = null;

                    if (logger.isDebugEnabled())
                        logger.debug("User " + userId + " is unknown to this gradebook");
                }
            } else {
                isKnown = false;
                userDisplayName = getLocalizedString("import_preview_unknown_name");
                userUid = null;
                userId = null;

                if (logger.isDebugEnabled())
                    logger.debug("Null userId in spreadsheet");
            }

        }

        public List getRowcontent() {

            return rowcontent;
        }

        public void setRowcontent(List rowcontent) {
            this.rowcontent = rowcontent;
        }

        public int getColumnCount() {
            return columnCount;
        }

        public void setColumnCount(int columnCount) {
            this.columnCount = columnCount;
        }

        public String getUserDisplayName() {
            return userDisplayName;
        }

        public void setUserDisplayName(String userDisplayName) {
            this.userDisplayName = userDisplayName;
        }

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }

        public String getUserUid() {
            return userUid;
        }

        public void setUserUid(String userUid) {
            this.userUid = userUid;
        }

        public boolean isKnown() {
            return isKnown;
        }

        public void setKnown(boolean known) {
            isKnown = known;
        }
    }

    //csv class to handle

    /** Parse comma-separated values (CSV), a common Windows file format.
     * Sample input: "LU",86.25,"11/4/1998","2:19PM",+4.0625
     * <p>
     * Inner logic adapted from a C++ original that was
     * Copyright (C) 1999 Lucent Technologies
     * Excerpted from 'The Practice of Programming'
     * by Brian W. Kernighan and Rob Pike.
     * <p>
     * Included by permission of the http://tpop.awl.com/ web site,
     * which says:
     * "You may use this code for any purpose, as long as you leave
     * the copyright notice and book citation attached." I have done so.
     * @author Brian W. Kernighan and Rob Pike (C++ original)
     * @author Ian F. Darwin (translation into Java and removal of I/O)
     * @author Ben Ballard (rewrote advQuoted to handle '""' and for readability)
     */
    class CSV {

        public static final char DEFAULT_SEP = ',';

        /** Construct a CSV parser, with the default separator (`,'). */
        public CSV() {
            this(DEFAULT_SEP);
        }

        /** Construct a CSV parser with a given separator.
         * @param sep The single char for the separator (not a list of
         * separator characters)
         */
        public CSV(char sep) {
            fieldSep = sep;
        }

        /** The fields in the current String */
        protected List list = new ArrayList();

        /** the separator char for this parser */
        protected char fieldSep;

        /** parse: break the input String into fields
         * @return java.util.Iterator containing each field
         * from the original as a String, in order.
         */
        public List parse(String line) {
            StringBuilder sb = new StringBuilder();
            list.clear(); // recycle to initial state
            int i = 0;

            if (line.length() == 0) {
                list.add(line);
                return list;
            }

            do {
                sb.setLength(0);
                if (i < line.length() && line.charAt(i) == '"')
                    i = advQuoted(line, sb, ++i); // skip quote
                else
                    i = advPlain(line, sb, i);
                list.add(sb.toString());
                i++;
            } while (i < line.length());
            if (logger.isDebugEnabled()) {
                StringBuilder logBuffer = new StringBuilder("Parsed " + line + " as: ");
                for (Iterator iter = list.iterator(); iter.hasNext();) {
                    logBuffer.append(iter.next());
                    if (iter.hasNext()) {
                        logBuffer.append(", ");
                    }
                }
                logger.debug(
                        "Parsed source string " + line + " as " + logBuffer.toString() + ", length=" + list.size());
            }
            return list;

        }

        /** advQuoted: quoted field; return index of next separator */
        protected int advQuoted(String s, StringBuilder sb, int i) {
            int j;
            int len = s.length();
            for (j = i; j < len; j++) {
                if (s.charAt(j) == '"' && j + 1 < len) {
                    if (s.charAt(j + 1) == '"') {
                        j++; // skip escape char
                    } else if (s.charAt(j + 1) == fieldSep) { //next delimeter
                        j++; // skip end quotes
                        break;
                    }
                } else if (s.charAt(j) == '"' && j + 1 == len) { // end quotes at end of line
                    break; //done
                }
                sb.append(s.charAt(j)); // regular character.
            }
            return j;
        }

        /** advPlain: unquoted field; return index of next separator */
        protected int advPlain(String s, StringBuilder sb, int i) {
            int j;

            j = s.indexOf(fieldSep, i); // look for separator
            if (j == -1) { // none found
                sb.append(s.substring(i));
                return s.length();
            } else {
                sb.append(s.substring(i, j));
                return j;
            }
        }
    }

    //************************ EXCEL file parsing *****************************
    /**
     * method converts an input stream to an List consisting of strings
     * representing a line.  The input stream must be for an xls file.
     *
     * @param inputStream
     * @return contents
     */
    private List excelToArray(InputStream inputStreams) throws IOException {
        HSSFWorkbook wb = new HSSFWorkbook(inputStreams);

        //Convert an Excel file to csv
        HSSFSheet sheet = wb.getSheetAt(0);
        List array = new ArrayList();
        Iterator it = sheet.rowIterator();
        while (it.hasNext()) {
            HSSFRow row = (HSSFRow) it.next();
            String rowAsString = fromHSSFRowtoCSV(row);
            if (rowAsString.replaceAll(",", "").replaceAll("\"", "").equals("")) {
                continue;
            }
            array.add(fromHSSFRowtoCSV(row));
        }
        return array;
    }

    private String fromHSSFRowtoCSV(HSSFRow row) {
        StringBuffer csvRow = new StringBuffer();
        int l = row.getLastCellNum();
        for (int i = 0; i < l; i++) {
            HSSFCell cell = row.getCell((short) i);
            String cellValue = "";
            if (cell == null || cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
                cellValue = "";
            } else if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
                cellValue = "\"" + cell.getStringCellValue() + "\"";
            } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
                double value = cell.getNumericCellValue();
                cellValue = getNumberFormat().format(value);
                cellValue = "\"" + cellValue + "\"";
            }

            csvRow.append(cellValue);

            if (i < l) {
                csvRow.append(getCsvDelimiter().toCharArray()[0]);
            }
        }
        return csvRow.toString();

    }

    /**
     * Parse newer OOXML Excel Spreadsheets
     * @param inputStreams
     * @return
     * @throws IOException
     */
    private List<String> excelOOXMLToArray(InputStream inputStreams) throws IOException {
        XSSFWorkbook wb = new XSSFWorkbook(inputStreams);

        //Convert an Excel OOXML (.xslx) file to csv
        XSSFSheet sheet = wb.getSheetAt(0);
        List<String> array = new ArrayList<String>();
        Iterator it = sheet.rowIterator();
        while (it.hasNext()) {
            XSSFRow row = (XSSFRow) it.next();
            String rowAsString = fromXSSFRowtoCSV(row);
            if (rowAsString.replaceAll(",", "").replaceAll("\"", "").equals("")) {
                continue;
            }
            array.add(fromXSSFRowtoCSV(row));
        }
        return array;
    }

    private String fromXSSFRowtoCSV(XSSFRow row) {
        StringBuffer csvRow = new StringBuffer();
        int l = row.getLastCellNum();
        for (int i = 0; i < l; i++) {
            XSSFCell cell = row.getCell((short) i);
            String cellValue = "";
            if (cell == null || cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
                cellValue = "";
            } else if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
                cellValue = "\"" + cell.getStringCellValue() + "\"";
            } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
                double value = cell.getNumericCellValue();
                cellValue = getNumberFormat().format(value);
                cellValue = "\"" + cellValue + "\"";
            }

            csvRow.append(cellValue);

            if (i < l) {
                csvRow.append(getCsvDelimiter().toCharArray()[0]);
            }
        }
        return csvRow.toString();
    }

    /**
     * Process an upload ActionEvent from spreadsheetUpload.jsp or spreadsheetEntireGBImport.jsp
     * Source of this action is the Upload button on either page
     *
     * @param event
     */
    public void launchFilePicker(ActionEvent event) {
        try {
            String titleText = FacesUtil.getLocalizedString("upload_view_page_title");
            String instructionText = FacesUtil.getLocalizedString("upload_view_instructions_text");

            ToolSession currentToolSession = SessionManager.getCurrentToolSession();
            // SAK-14173 - store title
            currentToolSession.setAttribute(IMPORT_TITLE, this.title);
            currentToolSession.setAttribute(FilePickerHelper.FILE_PICKER_MAX_ATTACHMENTS,
                    FilePickerHelper.CARDINALITY_SINGLE);
            currentToolSession.setAttribute(FilePickerHelper.FILE_PICKER_TITLE_TEXT, titleText);
            currentToolSession.setAttribute(FilePickerHelper.FILE_PICKER_INSTRUCTION_TEXT, instructionText);
            currentToolSession.setAttribute(FilePickerHelper.FILE_PICKER_RESOURCE_FILTER,
                    ComponentManager.get("org.sakaiproject.content.api.ContentResourceFilter.spreadsheetCsvFile"));
            ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
            context.redirect("sakai.filepicker.helper/tool");
        } catch (Exception e) {
            logger.error(this + ".launchFilePicker - " + e);
            e.printStackTrace();
        }
    }

    /**
     * SAK-14173 - This event will cause the title to be stored in the bean so that it can be stored
     * in the session when the user goes to choose a file and will not be lost
     * @param event JSF value change event
     */
    public void changeTitle(ValueChangeEvent event) {
        this.title = (String) event.getNewValue();
    }

    /**
     * SAK-14173 - Clears all the session variables stored as part of the spreadsheet upload code
     * @param event JSF event
     */
    public void cancelAndClearSession(ActionEvent event) {
        clearImportTitle();
        clearPickedFile();
    }

    /**
     * SAK-14173 - Clears the import title from the session
     */
    private void clearImportTitle() {
        ToolSession currentToolSession = SessionManager.getCurrentToolSession();
        currentToolSession.removeAttribute(IMPORT_TITLE);
    }

    /**
     * Extract and store the reference to the uploaded file.
     * Only process the first reference - don't do multiple uploads.
     *
     */
    public void savePickedUploadFile() {
        ToolSession session = SessionManager.getCurrentToolSession();
        if (session.getAttribute(PICKED_FILE_REFERENCE) != null) {
            pickedFileReference = (String) session.getAttribute(PICKED_FILE_REFERENCE);
            pickedFileDesc = (String) session.getAttribute(PICKED_FILE_DESC);
        }
    }

    /**
     * Use the uploaded file reference to get an InputStream.
     * Must be a reference to a ContentResource
     * @param resource the ContentResource associated with {@link #pickedFileReference}.
     * see {@link #getPickedContentResource()}
     * @return InputStream
     */
    private InputStream getPickedFileStream(ContentResource resource) {
        InputStream inStream = null;

        if (resource != null) {
            try {
                inStream = resource.streamContent();
            } catch (ServerOverloadException soe) {
                logger.error(soe.getStackTrace());
            }
        }

        return inStream;
    }

    /**
     *
     * @return the ContentResource associated with the {@link #pickedFileReference} property.
     * returns null if the entity is not a ContentResource
     */
    private ContentResource getPickedContentResource() {
        ContentResource resource = null;
        if (pickedFileReference != null) {
            Reference ref = EntityManager.newReference(pickedFileReference);
            if (ref != null) {
                Entity ent = ref.getEntity();
                if (ent instanceof ContentResource) {
                    // entity came from file picker, so it should be a content resource
                    resource = (ContentResource) ent;
                }
            }
        }

        return resource;
    }

    private void clearPickedFile() {
        ToolSession session = SessionManager.getCurrentToolSession();
        session.removeAttribute(PICKED_FILE_REFERENCE);
        session.removeAttribute(PICKED_FILE_DESC);

        pickedFileDesc = null;
        pickedFileReference = null;
    }

    /**
     * @return the pickedFileDesc
     */
    public String getPickedFileDesc() {
        // check the session attribute first
        ToolSession session = SessionManager.getCurrentToolSession();
        if (session.getAttribute(PICKED_FILE_DESC) != null) {
            pickedFileDesc = (String) session.getAttribute(PICKED_FILE_DESC);
        }

        return pickedFileDesc;
    }

    /**
     * @param pickedFileDesc the pickedFileDesc to set
     */
    public void setPickedFileDesc(String pickedFileDesc) {
        this.pickedFileDesc = pickedFileDesc;
    }

    /**
     *
     * @return the number of users with the student-type role enrolled in the current site
     */
    private int getNumStudentsInSite() {
        List enrollments = getSectionAwareness().getSiteMembersInRole(getGradebookUid(), Role.STUDENT);
        int numStudentsInSite = enrollments != null ? enrollments.size() : 0;
        return numStudentsInSite;
    }

    private String getCsvDelimiter() {
        if (csvDelimiter == null) {
            csvDelimiter = ServerConfigurationService.getString("csv.separator", ",");
        }

        return csvDelimiter;
    }

    /**
     *
     * @param doubleAsString
     * @return a locale-aware Double value representation of the given String
     * @throws ParseException
     */
    private Double convertStringToDouble(String doubleAsString) throws ParseException {
        Double scoreAsDouble = null;
        if (doubleAsString != null) {
            Number numericScore = getNumberFormat().parse(doubleAsString.trim());
            scoreAsDouble = numericScore.doubleValue();
        }

        return scoreAsDouble;
    }

    private NumberFormat getNumberFormat() {
        if (numberFormat == null) {
            numberFormat = NumberFormat.getInstance(new ResourceLoader().getLocale());
        }

        return numberFormat;
    }

    public String getDateEntryFormatDescription() {
        return this.date_entry_format_description;
    }

    public Boolean getExtraCreditCatSelected() {
        return extraCreditCatSelected;
    }
}