class IdGeneratorService {

    public synchronized long generate(int shardId) {
        if (shardId > maxShardId || shardId < 0) {
            throw new IllegalArgumentException(format("Shard id can't be greater than %s or less than 0", maxShardId));
        }

        long ts = currentTimeMillis();

        if (ts < lastTimestamp) {
            log.error("Clock is moving backwards. Rejecting requests until {}.", lastTimestamp);
            throw new IllegalStateException(format("Clock moved backwards. Refusing to generate id for %s milliseconds", lastTimestamp - ts));
        }

        if (lastTimestamp == ts || lastTimestamp < 0) {
            sequence++;
        } else {
            sequence = 0;
        }

        // omg, too many photo for one shard!
        if (sequence > maxSequenceId) {
            ts = getNextMills(lastTimestamp);
            sequence = 0;
        }

        lastTimestamp = ts;

        return ((ts - epoch) << timestampLeftShift) |
                (shardId << shardIdShift) |
                sequence;
    }

}