package td2jira.jira.soap;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import td2jira.Config;
import td2jira.jira.IJIRAConnector;
import td2jira.jira.JIRAComment;
import td2jira.jira.JIRAIssue;

import com.atlassian.jira.rpc.soap.beans.RemoteAttachment;
import com.atlassian.jira.rpc.soap.beans.RemoteComment;
import com.atlassian.jira.rpc.soap.beans.RemoteField;
import com.atlassian.jira.rpc.soap.beans.RemoteFieldValue;
import com.atlassian.jira.rpc.soap.beans.RemoteIssue;
import com.atlassian.jira.rpc.soap.jirasoapservice_v2.JiraSoapService;
import com.atlassian.jira.rpc.soap.jirasoapservice_v2.JiraSoapServiceService;
import com.atlassian.jira.rpc.soap.jirasoapservice_v2.JiraSoapServiceServiceLocator;

public class JIRASoapConnector implements IJIRAConnector {
	private static Logger logger = Logger.getLogger(JIRASoapConnector.class);
	
	JiraSoapService svc;
	String token;
	
	public void addAttachment(JIRAIssue jiraIssue, String fileName, byte[] data) {
		try {
			logger.info("adding attachment "+fileName+" ("+data.length+" bytes) to "+jiraIssue.getKey()+"...");
			if( !svc.addAttachmentsToIssue(token, jiraIssue.getKey(), new String[]{fileName}, new byte[][]{ data }) ) throw new RuntimeException("failed to add attachment");
			logger.info("done");
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		} 
	}

	public void addComment(JIRAIssue jt, String comment) {
		try {
			logger.info("adding comment to "+jt.getKey());
			logger.info(comment);
			RemoteComment rc = new RemoteComment();
			rc.setBody(comment);
			rc.setAuthor(Config.JIRA_USER);
			svc.addComment(token, jt.getKey(), rc);
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}

	public void closeIssue(JIRAIssue jiraIssue) {
		try {
			final String closedMarker = "(CLOSED@TD)";
			String summary = jiraIssue.getSummary();
			if( summary.indexOf(closedMarker) >= 0 ) return;
			jiraIssue.setSummary(closedMarker+summary);
			logger.info("marking "+jiraIssue.getKey()+" issue as to be closed");
			updateSummary(jiraIssue);
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}

	public void createJIRATask(JIRAIssue jiraIssue) {
		try {
			RemoteIssue issue = new RemoteIssue();
			issue.setProject(jiraIssue.getProjectId());
			issue.setType("1");
			issue.setSummary(jiraIssue.getSummary());
			issue.setDescription(jiraIssue.getDescription());
			issue.setAssignee(jiraIssue.getAssignee());
			issue = svc.createIssue(token, issue);
	
			logger.info("new JIRA issue "+issue.getKey()+" has been created");
			jiraIssue.setKey(issue.getKey());
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}

	public List<JIRAIssue> findTasks(String query) {
		try {
			RemoteIssue[] issues = svc.getIssuesFromTextSearch(token, query);
			
			List<JIRAIssue> tasks = new ArrayList<JIRAIssue>();
			for (RemoteIssue issue : issues) {
				JIRAIssue ji = new JIRAIssue();
				ji.setKey(issue.getKey());
				ji.setAssignee(issue.getAssignee());
				ji.setDescription(issue.getDescription());
				ji.setProjectId(issue.getProject());
				ji.setStatus(issue.getStatus());
				ji.setSummary(issue.getSummary());
				ji.setId(issue.getId());
				tasks.add(ji);
			}
			
			return tasks;
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}

	public List<String> getAttachmentsNames(JIRAIssue jiraIssue) {
		try {
			RemoteAttachment[] ras = svc.getAttachmentsFromIssue(token, jiraIssue.getKey());
			
			List<String> ans = new ArrayList<String>();
			for (RemoteAttachment attachment : ras) {
				ans.add(attachment.getFilename());
			}
			return ans;
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}

	public Map[] getComponents() {
		return null;
	}

	public Map[] getProjects() {
		return null;
	}

	public Map getUser(String userName) {
		return null;
	}

	public Map[] getVersions() {
		return null;
	}

	public void login(String url, String projectName, String user,String password) {
		try {
			JiraSoapServiceService jiraSoapServiceGetter = new JiraSoapServiceServiceLocator();
			svc = jiraSoapServiceGetter.getJirasoapserviceV2(new URL(url+"/rpc/soap/jirasoapservice-v2"));
			token = svc.login(user,password);
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}

	public void logout() {
		try {
			svc.logout(token);
		} catch( Exception ex ) {
		}
		token = null;
		svc = null;
	}

	public List<JIRAComment> getComments(JIRAIssue jt) {
		try {
			RemoteComment[] rcs = svc.getComments(token, jt.getKey());
			
			List<JIRAComment> jcs = new ArrayList<JIRAComment>();
			for (RemoteComment rc : rcs) {
				JIRAComment jc = new JIRAComment();
				jc.setAuthor(rc.getAuthor()); 
				jc.setAuthorFullName(rc.getAuthor());
				jc.setBody(rc.getBody());
				jc.setCreated(rc.getCreated().toString());
				jc.setId(rc.getId());
				jcs.add(jc);
			}
			
			return jcs;
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}

	private void updateSummary(JIRAIssue jiraIssue) {
		try {
			RemoteField[] fields = svc.getFieldsForEdit(token,jiraIssue.getKey());
			
			RemoteFieldValue rfv = new RemoteFieldValue();
			rfv.setValues(new String[]{jiraIssue.getSummary()});
			
			for (RemoteField field : fields) {
				if( field.getName().equals("summary") ) {
					rfv.setId(field.getId());
					break;
				}
			}
			
			svc.updateIssue(token, jiraIssue.getKey(),new RemoteFieldValue[]{rfv});
		} catch( Exception ex ) {
			throw new RuntimeException(ex);
		}
	}
}
