/*
 * Copyright (c) 2009 JSCAPE
 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JSCAPE. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 * the terms of the license agreement you entered into with JSCAPE.
 *
 */

package com.jscape.util.service;

/**
 * @author Alex Usun
 */
public abstract class AbstractService<T>
        implements Service<T> {

    protected State state;
    protected T context;

    protected AbstractService() {
        this.state = State.STOPPED;
    }

    public synchronized boolean isStarted() {
        return this.state == State.STARTED;
    }

    public synchronized void start(T context)
            throws ServiceException {
        assertNotStarted();
        assertNotDisposed();

        this.context = context;

        try {
            actualStart();
            this.state = State.STARTED;
        } catch (Throwable e) {
            throw ServiceException.wrap(e);
        }
    }

    public synchronized void stop() {
        if (isStarted()) {
            this.state = State.STOPPED;
            actualStop();
        }
    }

    public synchronized void dispose() {
        if (this.state == State.DISPOSED) {
            return;
        }

        if (this.state == State.STARTED) {
            stop();
        }

        this.state = State.DISPOSED;
        actualDispose();
    }

    public String toString() {
        return "AbstractService {"
                + "state=" + this.state
                + '}';
    }

    protected void actualStart()
            throws Exception {
        // empty
    }

    protected void actualStop() {
        // empty
    }

    protected void actualDispose() {
        // empty
    }

    protected void assertStarted()
            throws ServiceException {
        if (!isStarted()) {
            throw new ServiceException("Service is not started.");
        }
    }

    protected void assertNotStarted()
            throws ServiceException {
        if (isStarted()) {
            throw new ServiceException("Service is already started.");
        }
    }

    protected void assertNotDisposed()
            throws ServiceException {
        if (this.state == State.DISPOSED) {
            throw new ServiceException("Service is disposed.");
        }
    }

    public enum State {

        STARTED,
        STOPPED,
        DISPOSED

    }
}
